4.2 Dependency Injection

Spring has added annotation-based configuration support for dependency injection. These have already briefly been covered in the previous chapter, but only the basics were covered.

There are 4 annotations for dependency injection. They are @Autowired, @Configurable, @Qualifier, and @Resource. The @Autowired annotation autowires by type, but it can also be used along with the @Qualifier annotation to provide more specific autowiring behavior if there will be multiple beans of the same type in the IoC container. The @Configurable annotation is used to mark a class eligible for Spring dependency injection, but it's typically used with classes instantiated outside of the IoC container. This annotation is used along with the context:spring-configured element and will be covered in the AOP chapter since it's AOP related. The @Resource annotation autowires by name and is from JSR-250, which is the specification for Commons Annotations.

Table 4.3. Annotations from org.springframework.beans.factory.annotation

AnnotationSince VersionTargetDescription
@AutowiredSpring 2.5Constructor, Field, or Method If the AutowiredAnnotationBeanPostProcessor is registered with the IoC conatiner as the bean is processed, the constructor, field, or method is autowired by type.
@ConfigurableSpring 2.0Class Indicates a class is eligible for Spring configuration, but is typically only used with AspectJ and along with context:spring-configured.
@QualifierSpring 2.5Field or Parameter

Table 4.4. Annotations from javax.annotation

AnnotationSince VersionTargetDescription
@ResourceSpring 2.5Field or Method If the CommonAnnotationBeanPostProcessor is installed as the bean is processed, the field or method is autowired by name. Part of JSR-250 (Commons Annotations).

@Autowired with Constructors, Fields, and Methods

Without using any other annotations, @Autowired can autowire a constructor, field, or method by type. The AutowiredAnnotationBeanPostProcessor must be registered with either the BeanFactory or ApplicationContext to have annotation-based autowiring on beans work. This bean post processor is implicitly registered by context:component-scan and context:annotation-config. Both of which will be covered in more detail in the following section.

When @Autowired is unable to find at least one match, a BeanCreationException will be thrown. By default it required that it autowires at least one value, but this can be changed by setting @Autowired(required=false). If more than one match is found when matching by type and it isn't an array or Collection class, a BeanCreationException will be thrown. If there is one bean that should be selected out of many of the same type, the bean element's primary attribute can be set to true. This will let autowiring by type pick a unique bean from a list of beans that are all the same type. There must be only one bean marked as the primary bean for a type or an exception will still be thrown.

One or more parameters can be autowired for a constructor or method. Only one constructor can be marked as required, although more than one can be set as autowired. If there is more than one constructor marked as autowired, Spring will use the constructor that can have the most arguments matched based on the beans in the IoC container and the autowiring rules.

Example 4.1. @Autowired Constructor

The two different parameters will be autowired by type. As previously mentioned, there must only be one bean defined in the container of each type being autowired or there will be an error.

Excerpt from chapter04-annotation-based-autowire/src/main/java/org/springbyexample/springindepth/chapter04/annotationBasedAutowire/ConstructorContainer.java
                    
@Autowired
public ConstructorContainer(MockDatasource mockDatasource, MockRemoteService mockRemoteService) {
                    
                

Example 4.2. @Autowired Field

Based on the type of the field, a MockDatasource bean is set on the field. There must be only one matching bean.

Excerpt from chapter04-annotation-based-autowire/src/main/java/org/springbyexample/springindepth/chapter04/annotationBasedAutowire/AutowiredTest.java
                    
@Autowired
protected MockDatasource mockDatasource = null;
                    
                

Example 4.3. @Autowired Method

The autowired method has a MockDatasource bean set on the method. There must be only one matching bean.

Excerpt from chapter04-annotation-based-autowire/src/main/java/org/springbyexample/springindepth/chapter04/annotationBasedAutowire/AutowiredTest.java
                    
protected MockDatasource methodMockDatasource = null;

@Autowired
public void setMockDatasource(MockDatasource methodMockDatasource) {
    this.methodMockDatasource = methodMockDatasource;
}
                    
                

@Autowired Collections

Collections can also be autowired. @Autowired can be used to autowire arrays, Java 5 typed Collections, and Java 5 type Maps. This can be used anywhere @Autowired will work (constructors, fields, and methods). All beans of the array's type or a Java 5 type collection (Collection, List, Set) will be set on a constructor, field, or method. A Java 5 typed Map will have all beans matching the type of the value set on it. The Map's key must be a java.lang.String which will be set with the name of the bean and the value will be the actual bean.

Example 4.4. @Autowired Array

This is an example of an array being autowired as a class level variable and also through a method. All beans of the array's type will be set on the field and method.

Excerpt from chapter04-annotation-based-autowire/src/main/java/org/springbyexample/springindepth/chapter04/annotationBasedAutowire/AutowiredCollectionTest.java
                    
@Autowired
protected MockDatasource[] mockDatasource = null;

protected MockDatasource[] methodMockDatasource = null;

@Autowired
public void setMethodMockDatasource(MockDatasource[] methodMockDatasource) {
    this.methodMockDatasource = methodMockDatasource;
}
                    
                

Example 4.5. @Autowired Java 5 Type Collection

All beans matching the List's generic type will be set on the field and method.

Excerpt from chapter04-annotation-based-autowire/src/main/java/org/springbyexample/springindepth/chapter04/annotationBasedAutowire/AutowiredCollectionTest.java
                    
@Autowired
protected List<MockDatasource> lMockDatasources = null;

protected List<MockDatasource> lMethodMockDatasources = null;

@Autowired
public void setMethodMockDatasourceList(List<MockDatasource> lMethodMockDatasources) {
    this.lMethodMockDatasources = lMethodMockDatasources;
}
                    
                

Example 4.6. @Autowired Java 5 Type Map

All beans matching the Map's generic type value will be set on the field and method, and the key will be the bean's name.

Excerpt from chapter04-annotation-based-autowire/src/main/java/org/springbyexample/springindepth/chapter04/annotationBasedAutowire/AutowiredCollectionTest.java
                    
@Autowired
protected Map<String, MockDatasource> hMockDatasource = null;

protected Map<String, MockDatasource> hMethodMockDatasources = null;

@Autowired
public void setMethodMockDatasourceMap(Map<String, MockDatasource> hMethodMockDatasources) {
    this.hMethodMockDatasources = hMethodMockDatasources;
}
                    
                

@Autowired & @Qualifier with Constructors, Fields, and Methods

The @Qualifier annotation is used exclusively along with the @Autowired. The simplest usage of @Qualifier is to pass in a bean name. This changes the autowiring from by type to by name wherever @Qualifier specifies a name. This is the equivalent of using the @Resource annotation when used on a field or method, but using @Autowired with @Qualifier is much more flexible since it can also be used with constructors and multiple parameter methods. If there isn't a match and @Autowired is marked as required, then a BeanCreationException will be thrown. When @Qualifier is used on constructors or methods with multiple parameters, any parameters without the annotation will still be autowired by type.

Example 4.7. @Autowired & @Qualifier Constructor

This example shows adding an @Qualifier for each parameter specifying a bean name that should be autowired.

Excerpt from chapter04-annotation-based-autowire/src/main/java/org/springbyexample/springindepth/chapter04/annotationBasedAutowire/QualifierConstructorContainer.java
                    
@Autowired
public QualifierConstructorContainer(@Qualifier("albumDatasource")MockDatasource mockDatasource, 
                                     @Qualifier("albumCoverRemoteService")MockRemoteService mockRemoteService) {
                    
                

Example 4.8. @Autowired & @Qualifier Field

Each field is autowired by name based on the value set on the @Qualifier annotation.

Excerpt from chapter04-annotation-based-autowire/src/test/java/org/springbyexample/springindepth/chapter04/annotationBasedAutowire/AutowiredQualifierNameTest.java
                    
@Autowired
@Qualifier("personDatasource")
protected MockDatasource personMockDatasource = null;

@Autowired
@Qualifier("albumDatasource")
protected MockDatasource albumMockDatasource = null;
                    
                

Example 4.9. @Autowired & @Qualifier Method

Each method is autowired by name based on the @Qualifier on the parameter of the method.

Excerpt from chapter04-annotation-based-autowire/src/test/java/org/springbyexample/springindepth/chapter04/annotationBasedAutowire/AutowiredQualifierNameTest.java
                    
protected MockDatasource methodPersonMockDatasource = null;

@Autowired
public void setPersonMockDatasource(@Qualifier("personDatasource")MockDatasource methodPersonMockDatasource) {
    this.methodPersonMockDatasource = methodPersonMockDatasource;
}
                    
                
Excerpt from chapter04-annotation-based-autowire/src/test/java/org/springbyexample/springindepth/chapter04/annotationBasedAutowire/AutowiredQualifierNameTest.java
                    
@Autowired
public void setMockDatasources(@Qualifier("personDatasource")MockDatasource multipleParamPersonMockDatasource,
                               @Qualifier("albumDatasource")MockDatasource multipleParamAlbumMockDatasource) {
    this.multipleParamPersonMockDatasource = multipleParamPersonMockDatasource;
    this.multipleParamAlbumMockDatasource = multipleParamAlbumMockDatasource;
}
                    
                

@Autowired & Custom Qualifiers

Custom qualifiers can also be created to use with the @Autowired annotation. A custom annotation class just needs to have the @Qualifier annotation added to it to identify it as a custom qualifier. Then beans marked with extra meta data either using the bean element's qualifier or meta sub-elements can be matched with a custom qualifier annotation. This provides a more detailed and meaningful annotation than just referencing a bean by type or name. The simplest custom qualifier could just be creating an annotation. For example, @Personal and @Work annotations could be made just to autowire address beans to the correct address field. Obviously more meta data than this would really be needed since you need a unique match and would have many addresses in a real system, but it gives the general idea on how this might be used. Another example would be to create an @AddressType annotation that takes a value. Then it could be set as @AddressType(“personal”) or @AddressType(“work”). As many values that are necessary to define a custom annotation can be used. In the XML configuration file, a bean can have extra meta data given to it by using the qualifier or meta sub-elements. The qualifier element will be used in preference to the meta element if it's available. When using the qualifier element, the custom annotation that this metadata applies to is specified. The meta element is more generic and could possibly be used to match to multiple custom qualifiers.

Example 4.10. Simple Custom Qualifier

This is an example of a simple custom qualifier that takes a String as extra metadata. The class is annotated with @Qualifier which is used to identify it as a custom qualifier annotation class. The @Target annotation indicates this annotation can be used on fields and parameters (constructor or method).

Excerpt from chapter04-annotation-based-autowire/src/test/java/org/springbyexample/springindepth/chapter04/annotationBasedAutowire/Datasource.java
                    
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Datasource {

    String value();

}
                    
                

Example 4.11. @Autowired & Simple Custom Qualifier Field

The fields will be autowired by matching the @Datasource annotation and it's value.

Excerpt from chapter04-annotation-based-autowire/src/test/java/org/springbyexample/springindepth/chapter04/annotationBasedAutowire/AutowiredSimpleCustomQualifierTest.java
                    
@Autowired
@Datasource("person")
protected MockDatasource personMockDatasource = null;

@Autowired
@Datasource("album")
protected MockDatasource albumMockDatasource = null;
                    
                

The two different datasources use the qualifier element to identify the annotation type of the custom qualifier and also it's value. The qualifier element's type attribute can be set with either the annotation's class name or the full package and class name. If only the class name is set and the name is unique, Spring will find it.

Excerpt from chapter04-annotation-based-autowire/src/main/resources/org/springbyexample/springindepth/chapter04/annotationBasedAutowire/AutowiredSimpleCustomQualifierTest-context.xml
                    
<bean id="personDatasource" 
      class="org.springbyexample.springindepth.chapter04.annotationBasedAutowire.MockDatasource">
    <qualifier type="Datasource" value="person" />
</bean>

<bean id="albumDatasource" 
      class="org.springbyexample.springindepth.chapter04.annotationBasedAutowire.MockDatasource">
    <qualifier type="org.springbyexample.springindepth.chapter04.annotationBasedAutowire.Datasource" 
                    value="album" />
</bean>
                    
                

Example 4.12. @Autowired & Simple Custom Qualifier Method

Notice that the custom qualifier annotation is used directly on the method parameter(s).

Excerpt from chapter04-annotation-based-autowire/src/test/java/org/springbyexample/springindepth/chapter04/annotationBasedAutowire/AutowiredSimpleCustomQualifierTest.java
                    
protected MockDatasource methodPersonMockDatasource = null;

@Autowired
public void setPersonMockDatasource(@Datasource("person")MockDatasource methodPersonMockDatasource) {
    this.methodPersonMockDatasource = methodPersonMockDatasource;
}
                    
                
Excerpt from chapter04-annotation-based-autowire/src/test/java/org/springbyexample/springindepth/chapter04/annotationBasedAutowire/AutowiredSimpleCustomQualifierTest.java
                    
protected MockDatasource multipleParamPersonMockDatasource = null;
protected MockDatasource multipleParamAlbumMockDatasource = null;

@Autowired
public void setMockDatasources(@Datasource("person")MockDatasource multipleParamPersonMockDatasource,
                                                     @Datasource("album")MockDatasource multipleParamAlbumMockDatasource) {
    this.multipleParamPersonMockDatasource = multipleParamPersonMockDatasource;
    this.multipleParamAlbumMockDatasource = multipleParamAlbumMockDatasource;
}
                    
                

Example 4.13. @Autowired & Custom Qualifier Field

This example's custom qualifier is the @RemoteService annotation which takes a service name and the enum RemoteType.

Excerpt from chapter04-annotation-based-autowire/src/test/java/org/springbyexample/springindepth/chapter04/annotationBasedAutowire/AutowiredCustomQualifierTest.java
                    
@Autowired
@RemoteService(service="phoneNumber", type=RemoteType.SOAP)
protected MockRemoteService phoneNumberMockRemoteService = null;

@Autowired
@RemoteService(service="albumCover", type=RemoteType.EJB)
protected MockRemoteService albumCoverMockRemoteService = null;
                    
                

The phoneNumberRemoteService bean uses the qualifier element and it's attribute sub-element to define the metadata used during autowiring. The albumCoverRemoteService bean uses meta elements to define it's metadata. Notice that it doesn't explicitly define what custom qualifier the metadata should be used with.

Excerpt from chapter04-annotation-based-autowire/src/main/resources/org/springbyexample/springindepth/chapter04/annotationBasedAutowire/AutowiredCustomQualifierTest-context.xml
                    
<bean id="phoneNumberRemoteService" 
           class="org.springbyexample.springindepth.chapter04.annotationBasedAutowire.MockRemoteService">
    <qualifier type="RemoteService">
        <attribute key="service" value="phoneNumber"/>
        <attribute key="type" value="SOAP"/>
    </qualifier>
</bean>

<bean id="albumCoverRemoteService" 
           class="org.springbyexample.springindepth.chapter04.annotationBasedAutowire.MockRemoteService">
    <meta key="service" value="albumCover"/>
    <meta key="type" value="EJB"/>
</bean>
                    
                

Example 4.14. @Autowired & Simple Custom Qualifier Method

The method parameter(s) are marked with the @RemoteService annotation.

Excerpt from chapter04-annotation-based-autowire/src/test/java/org/springbyexample/springindepth/chapter04/annotationBasedAutowire/AutowiredCustomQualifierTest.java
                    
protected MockRemoteService methodPhoneMockRemoteService = null;

@Autowired
public void setPersonMockRemoteService(@RemoteService(service="phoneNumber", type=RemoteType.SOAP)
            MockRemoteService methodPhoneMockRemoteService) {
    this.methodPhoneMockRemoteService = methodPhoneMockRemoteService;
}
                    
                
Excerpt from chapter04-annotation-based-autowire/src/test/java/org/springbyexample/springindepth/chapter04/annotationBasedAutowire/AutowiredCustomQualifierTest.java
                    
protected MockRemoteService multipleParamPhoneMockRemoteService = null;
protected MockRemoteService multipleParamAlbumMockRemoteService = null;

@Autowired
public void setMockRemoteServices(@RemoteService(service="phoneNumber", type=RemoteType.SOAP)
		                MockRemoteService multipleParamPhoneMockRemoteService,
                                  	        @RemoteService(service="albumCover", type=RemoteType.EJB)
		                MockRemoteService multipleParamAlbumMockRemoteService) {
    this.multipleParamPhoneMockRemoteService = multipleParamPhoneMockRemoteService;
    this.multipleParamAlbumMockRemoteService = multipleParamAlbumMockRemoteService;
}
                    
                

Autowired & CustomAutowireConfigurer

If you already have existing annotations that you would like to use as a custom qualifier or for some reason don't want to use the @Qualifier annotation, the CustomAutowireConfigurer class can be used to make an XML bean definition to register custom qualifiers. Once they are registered, they will behave exactly like one annotated with the @Qualifier annotation during the autowiring process.

Example 4.15. @Autowired & CustomAutowireConfigurer

This example is the same as the previous simple custom qualifier example using @Datasource. The only difference is that @CustomDatasource doesn't have the @Qualifier annotation.

Excerpt from chapter04-annotation-based-autowire/src/main/resources/org/springbyexample/springindepth/chapter04/annotationBasedAutowire/CustomAutowireConfigurerQualifierTest.java
                    
@Autowired
@CustomDatasource("person")
protected MockDatasource personMockDatasource = null;

@Autowired
@CustomDatasource("album")
protected MockDatasource albumMockDatasource = null;
                    
                

Once the CustomDatasource annotation class is registered with CustomAutowireConfigurer, it can be used as a custom qualifier during the autowiring process.

Excerpt from chapter04-annotation-based-autowire/src/main/resources/org/springbyexample/springindepth/chapter04/annotationBasedAutowire/CustomAutowireConfigurerQualifierTest-context.xml
                    
<bean id="customAutowireConfigurer" 
           class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
    <property name="customQualifierTypes">
        <set>
            <value>org.springbyexample.springindepth.chapter04.annotationBasedAutowire.CustomDatasource</value>
        </set>
    </property>
</bean>
           
<bean id="personDatasource" 
           class="org.springbyexample.springindepth.chapter04.annotationBasedAutowire.MockDatasource">
    <qualifier type="CustomDatasource" value="person" />
</bean>

<bean id="albumDatasource" 
           class="org.springbyexample.springindepth.chapter04.annotationBasedAutowire.MockDatasource">
    <meta key="value" value="album" />
</bean>
                    
                

Dependency Injection Validation

The @Required annotation can be set on a method that must have a value injected into it. It doesn't matter if the method is injected because of the XML configuration or by using annotation-based configuration. This annotation is very useful for marking a critical resource that should be dependency injected. Like a remote resource, datasource, or a DAO instance. To have this annotation processed the RequiredAnnotationBeanPostProcessor must be configured in the IoC container. The context:annotation-config element automatically registers this bean post processor.

Table 4.5. Annotations from org.springframework.beans.factory.annotation

AnnotationSince VersionTargetDescription
@RequiredSpring 2.0Method If the RequiredAnnotationBeanPostProcessor is installed, a method must be injected with a value during it's creation or an error is thrown.