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
| Annotation | Since Version | Target | Description |
|---|---|---|---|
@Autowired | Spring 2.5 | Constructor, 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.
|
@Configurable | Spring 2.0 | Class | Indicates a class is eligible for Spring configuration, but is typically only used with AspectJ and along with context:spring-configured. |
@Qualifier | Spring 2.5 | Field or Parameter |
Table 4.4. Annotations from javax.annotation
| Annotation | Since Version | Target | Description |
|---|---|---|---|
@Resource | Spring 2.5 | Field 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).
|
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;
}
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;
}
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.
@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.
@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.
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;
}
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).
@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.
@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.
@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.
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;
}
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.
<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>
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
| Annotation | Since Version | Target | Description |
|---|---|---|---|
@Required | Spring 2.0 | Method |
If the RequiredAnnotationBeanPostProcessor is installed, a method must be injected with a value during it's creation or an error is thrown.
|