Google

May 3, 2013

Wiring up Spring framework Dependency Injection with annotations

Q13. How will you go about wire components using Spring annotations?
A13. Here are the high level steps involved in wiring up a web application in Spring using annotations.

web.xml --> myAppServletContext.xml --> myapp-applicationContext.xml --> MyAppController.java --> MyAppService.Java --> MyAppDaoImpl.java

Pay attention to how the different artifacts are wired up using both Spring xml files and annotations. The Spring beans can be wired either by name or type. @Autowired by default is a type driven injection. @Autowired is Spring annotation, while @Inject is a JSR-330 annotation. @Inject is equivalent to @Autowired or @Autowired(required=true). @Qualifier spring annotation can be used to further fine-tune auto-wiring. There may be a situation when you create more than one bean of the same type and want to wire only one of them with a property, in such case you can use @Qualifier annotation along with @Autowired to remove the confusion by specifying which exact bean will be wired.

The Step 3: demonstrates "name" driven wiring up using annotations.

Step 1: The web.xml file snippet.


 <servlet>
  <servlet-name>myAppServlet</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <init-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>/META-INF/spring/myAppServletContext.xml</param-value>
  </init-param>
  <load-on-startup>2</load-on-startup>
 </servlet>

  <!-- Creates the Spring Container shared by all Servlets and Filters -->
    <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

  <-- add resolvers here, if required-->
  
 <servlet-mapping>
  <servlet-name>myAppServlet</servlet-name>
  <url-pattern>/myapp/*</url-pattern>
 </servlet-mapping>

Step 2: The myAppServletContext.xml file snippet.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
 xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:cache="http://www.springframework.org/schema/cache"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jee="http://www.springframework.org/schema/jee"
 xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util"
 xmlns:batch="http://www.springframework.org/schema/batch" xmlns:cm="http://camel.apache.org/schema/spring"
 xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
            http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
            http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
         http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd 
         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 
            http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
            http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.1.xsd">

 
    <!-- import context files as it is not a best practice to define everything in one xml file-->
 <import resource="classpath:/META-INF/spring/myapp-applicationContext.xml" />
 
 <!-- scan for any Java based wiring up classes with @Configuration & @Bean annotations -->
 <context:component-scan base-package="com.myapp.camel.config" />
 
 
 <!-- exposing beans via JMX  not important for this tutorial -->
 <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter"
  lazy-init="false">
  <property name="autodetect" value="true"></property>
  <property name="namingStrategy" ref="namingStrategy"></property>
  <property name="assembler" ref="assembler"></property>
 </bean>
 <bean id="attributeSource"
  class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource" />
 <bean id="assembler"
  class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
  <property name="attributeSource" ref="attributeSource" />
 </bean>
 <bean id="namingStrategy"
  class="org.springframework.jmx.export.naming.MetadataNamingStrategy">
  <property name="attributeSource" ref="attributeSource" />
 </bean>

</beans>

 Step 3: The myapp-applicationContext.xml snippet with config to enable auto-scan with annotations.



As you can see, the controller, service, and DAO layer classes not configured here as they are scanned via annotation (i,e @Component is the parent annotation from which the other annotations like @Service, @Resource, @Repository etc are defined)

The annotations shown above allow you to declare beans that are to be picked up by autoscanning with <context:component-scan/> or @ComponentScan.


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jee="http://www.springframework.org/schema/jee"
 xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util"
    xmlns:security="http://www.springframework.org/schema/security"
 xmlns:batch="http://www.springframework.org/schema/batch" xmlns:task="http://www.springframework.org/schema/task"
 xmlns:mvc="http://www.springframework.org/schema/mvc"
 xsi:schemaLocation="
   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
   http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
   http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
   http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
   http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
   http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
   http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd">


 <mvc:annotation-driven />
 <context:annotation-config />
 
 <!-- load properties files -->
 <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
   <property name="ignoreUnresolvablePlaceholders" value="true"/> 
      <property name="location" value="classpath:/myapp/myapp.properties"/>
     <property name="placeholderPrefix" value="$myapp{"/>
  <property name="placeholderSuffix" value="}"/>
 </bean> 

 
    <!-- any packages to exclude for component scanning-->
 <context:component-scan base-package="com.myapp">
  <context:exclude-filter type="regex" expression="com.myapp.camel.config.MyAppCamelConfig"/>
 </context:component-scan>
 
 <!-- comment this line locally to bypass security access control in development. But don't check this in commented as security will be turned off -->
 <!-- Spring security-->
 <security:global-method-security secured-annotations="enabled" pre-post-annotations="enabled" jsr250-annotations="enabled"/>
 
</beans>



Step 4: The controller class that handles HTTP requests. Annotations are used to wire up dependencies.

@Controller
public class MyAppController
{
    
    
    private final MDCLoggingHelper MDCLoggingHelper = new MDCLoggingHelper();
    
  
    @Resource(name = "myapp_Service")
    private MyAppService myAppService; 
 
    
  @RequestMapping(
            value = "/portfolio/{portfoliocd}/summaries",
            method = RequestMethod.GET,
            produces = "application/json")
    @ResponseBody
    public PortfolioSummaryVO retrievePortfolioSummary(
            @PathVariable(value = "portfoliocd") String portfolioCode,
            @RequestParam(value = "valuationDate", required = true) @DateTimeFormat(pattern = "yyyyMMdd") Date valuationDate
            HttpServletResponse response) throws Exception
    {
 
   //..................
 }
 
}



Step 5: The service class that handles business logic in a protocol agnostic manner. Annotations are used to wire up dependencies.

@Service(value = "myapp_Service")
@Transactional(propagation = Propagation.SUPPORTS)
public class CashForecastServiceImpl implements CashForecastService
{
    
 @Resource(name = "myapp_Dao")
    private MyAppDao myAppDao;
 
 @Value("$cf{myapp.file_delimiter}")
    private String defaultFeedDelimiter; //read from myapp.properties files
 
  @Override
    public PortfolioSummaryVO  retrievePortfolioSummaries(MyAppPortfolioCriteria criteria,
            FeedFileMetaInfo feedFileMeta) {
 
        //.............. 
 }
}

Step 6: The DAO class that makes database calls via a JDBC template. The configuration of JDBC template is not shown.

@Repository(value = "myapp_Dao")
public class CashForecastDaoImpl implements CashForecastDao
{
    
    @Resource(name = "myapp_JdbcTemplate")
    private JdbcTemplate jdbcTemplateSybase;//configure via jdbcContext.xml
 
 
  public PortfolioSummaryVO  retrievePortfolioSummaries(MyAppPortfolioCriteria criteria) {
      //............
  }
 
}


The @Configuration annotation was designed as the replacement for XML configuration files. The @Configuration annotated classes can still able to use annotated(@Autowired, @Inject etc.) fields and properties to request beans (and even other @Configuration annotated beans too) from the container. Here is an example of how Apache Camel is wired up using the @configuration and @bean annotations in Step 2.

Labels:

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home