4.11 Annotation-based configuration

As mentioned in the section entitled Section 4.7.1.2, “Example: The RequiredAnnotationBeanPostProcessor”, using a BeanPostProcessor in conjunction with annotations is a common means of extending the Spring IoC container. For example, Spring 2.0 introduced the possibility of enforcing required properties with the @Required annotation. As of Spring 2.5, it is now possible to follow that same general approach to drive Spring's dependency injection. Essentially, the @Autowired annotation provides the same capabilities as described in Section 4.3.5, “Autowiring collaborators” but with more fine-grained control and wider applicability. Spring 2.5 also adds support for JSR-250 annotations such as @Resource, @PostConstruct, and @PreDestroy. Use of these annotations also requires that certain BeanPostProcessors be registered within the Spring container. As always, these can be registered as individual bean definitions, but they can also be implicitly registered by including the following tag in an XML-based Spring configuration (notice the inclusion of the 'context' namespace):

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd">
               
     <context:annotation-config/>
     
</beans>

(The implicitly registered post-processors include AutowiredAnnotationBeanPostProcessor, CommonAnnotationBeanPostProcessor, PersistenceAnnotationBeanPostProcessor, as well as the aforementioned RequiredAnnotationBeanPostProcessor.)

[Note]Note

Note that <context:annotation-config/> only looks for annotations on beans in the same application context it is defined in. This means that, if you put <context:annotation-config/> in a WebApplicationContext for a DispatcherServlet, it only checks for @Autowired beans in your controllers, and not your services. See Section 16.2, “The DispatcherServlet” for more information.

4.11.1 @Required

The @Required annotation applies to bean property setter methods, as in the following example:

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Required
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...
}

This annotation simply indicates that the affected bean property must be populated at configuration time: either through an explicit property value in a bean definition or through autowiring. The container will throw an exception if the affected bean property has not been populated; this allows for eager and explicit failure, avoiding NullPointerExceptions or the like later on. Note that it is still recommended to put assertions into the bean class itself (for example into an init method) in order to enforce those required references and values even when using the class outside of a container.

4.11.2 @Autowired

As expected, the @Autowired annotation may be applied to "traditional" setter methods:

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Autowired
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...
}

The annotation may also be applied to methods with arbitrary names and/or multiple arguments:

public class MovieRecommender {

    private MovieCatalog movieCatalog;
    
    private CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public void prepare(MovieCatalog movieCatalog, CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}

The @Autowired annotation may even be applied on constructors and fields:

public class MovieRecommender {

    @Autowired
    private MovieCatalog movieCatalog;
    
    private CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}

It is also possible to provide all beans of a particular type from the ApplicationContext by adding the annotation to a field or method that expects an array of that type:

public class MovieRecommender {

    @Autowired
    private MovieCatalog[] movieCatalogs;

    // ...
}

The same applies for typed collections:

public class MovieRecommender {

    private Set<MovieCatalog> movieCatalogs;
    
    @Autowired
    public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
        this.movieCatalogs = movieCatalogs;
    }

    // ...
}

Even typed Maps may be autowired as long as the expected key type is String. The Map values will contain all beans of the expected type, and the keys will contain the corresponding bean names:

public class MovieRecommender {

    private Map<String, MovieCatalog> movieCatalogs;
    
    @Autowired
    public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
        this.movieCatalogs = movieCatalogs;
    }

    // ...
}

By default, the autowiring will fail whenever zero candidate beans are available; the default behavior is to treat annotated methods, constructors, and fields as indicating required dependencies. This behavior can be changed as demonstrated below.

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Autowired(required=false)
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...
}
[Note]Note

Only one annotated constructor per-class may be marked as required, but multiple non-required constructors can be annotated. In that case, each will be considered among the candidates and Spring will use the greediest constructor whose dependencies can be satisfied.

Prefer the use of @Autowired's required attribute over the @Required annotation. The required attribute indicates that the property is not required for autowiring purposes, simply skipping it if it cannot be autowired. @Required, on the other hand, is stronger in that it enforces the property to have been set in any of the container's supported ways; if no value has been injected, a corresponding exception will be raised.

@Autowired may also be used for well-known "resolvable dependencies": the BeanFactory interface, the ApplicationContext interface, the ResourceLoader interface, the ApplicationEventPublisher interface and the MessageSource interface. These interfaces (and their extended interfaces such as ConfigurableApplicationContext or ResourcePatternResolver) will be automatically resolved, with no special setup necessary.

public class MovieRecommender {

    @Autowired
    private ApplicationContext context;

    public MovieRecommender() {
    }

    // ...
}

4.11.3 Fine-tuning annotation-based autowiring with qualifiers

Since autowiring by type may lead to multiple candidates, it is often necessary to have more control over the selection process. One way to accomplish this is with Spring's @Qualifier annotation. This allows for associating qualifier values with specific arguments, narrowing the set of type matches so that a specific bean is chosen for each argument. In the simplest case, this can be a plain descriptive value:

public class MovieRecommender {

    @Autowired
    @Qualifier("main")
    private MovieCatalog movieCatalog;

    // ...
}

The @Qualifier annotation can also be specified on individual constructor arguments or method parameters:

public class MovieRecommender {

    private MovieCatalog movieCatalog;
    
    private CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public void prepare(@Qualifier("main") MovieCatalog movieCatalog, CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}

The corresponding bean definitions would look like as follows. The bean with qualifier value "main" would be wired with the constructor argument that has been qualified with the same value.

<?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:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:annotation-config/>

    <bean class="example.SimpleMovieCatalog">
        <qualifier value="main"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <qualifier value="action"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean id="movieRecommender" class="example.MovieRecommender"/>

</beans>

For a fallback match, the bean name is considered as a default qualifier value. This means that the bean may be defined with an id "main" instead of the nested qualifier element, leading to the same matching result. However, note that while this can be used to refer to specific beans by name, @Autowired is fundamentally about type-driven injection with optional semantic qualifiers. This means that qualifier values, even when using the bean name fallback, always have narrowing semantics within the set of type matches; they do not semantically express a reference to a unique bean id. Good qualifier values would be "main" or "EMEA" or "persistent", expressing characteristics of a specific component - independent from the bean id (which may be auto-generated in case of an anonymous bean definition like the one above).

Qualifiers also apply to typed collections (as discussed above): e.g. to Set<MovieCatalog>. In such a case, all matching beans according to the declared qualifiers are going to be injected as a collection. This implies that qualifiers do not have to be unique; they rather simply constitute filtering criteria. For example, there could be multiple MovieCatalog beans defined with the same qualifier value "action"; all of which would be injected into a Set<MovieCatalog> annotated with @Qualifier("action").

[Tip]Tip

If you intend to express annotation-driven injection by name, do not primarily use @Autowired - even if is technically capable of referring to a bean name through @Qualifier values. Instead, prefer the JSR-250 @Resource annotation which is semantically defined to identify a specific target component by its unique name, with the declared type being irrelevant for the matching process.

As a specific consequence of this semantic difference, beans which are themselves defined as a collection or map type cannot be injected via @Autowired since type matching is not properly applicable to them. Use @Resource for such beans, referring to the specific collection/map bean by unique name.

Note: In contrast to @Autowired which is applicable to fields, constructors and multi-argument methods (allowing for narrowing through qualifier annotations at the parameter level), @Resource is only supported for fields and bean property setter methods with a single argument. As a consequence, stick with qualifiers if your injection target is a constructor or a multi-argument method.

You may create your own custom qualifier annotations as well. Simply define an annotation and provide the @Qualifier annotation within your definition:

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Genre {

    String value();
}

Then you can provide the custom qualifier on autowired fields and parameters:

public class MovieRecommender {

    @Autowired
    @Genre("Action")
    private MovieCatalog actionCatalog;
    
    private MovieCatalog comedyCatalog;
    
    @Autowired
    public void setComedyCatalog(@Genre("Comedy") MovieCatalog comedyCatalog) {
        this.comedyCatalog = comedyCatalog;
    }

    // ...
}

The next step is to provide the information on the candidate bean definitions. You can add <qualifier/> tags as sub-elements of the <bean/> tag and then specify the 'type' and 'value' to match your custom qualifier annotations. The type will be matched against the fully-qualified class name of the annotation, or as a convenience when there is no risk of conflicting names, you may use the 'short' class name. Both are demonstrated in the following example.

<?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:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:annotation-config/>

    <bean class="example.SimpleMovieCatalog">
        <qualifier type="Genre" value="Action"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <qualifier type="example.Genre" value="Comedy"/>
        <!-- inject any dependencies required by this bean -->
    </bean>
    
    <bean id="movieRecommender" class="example.MovieRecommender"/>

</beans>

In the next section, entitled Section 4.12, “Classpath scanning, managed components and writing configurations using Java”, you will see an annotation-based alternative to providing the qualifier metadata in XML. Specifically, see: Section 4.12.9, “Providing qualifier metadata with annotations”.

In some cases, it may be sufficient to use an annotation without a value. This may be useful when the annotation serves a more generic purpose and could be applied across several different types of dependencies. For example, you may provide an offline catalog that would be searched when no Internet connection is available. First define the simple annotation:

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Offline {

}

Then add the annotation to the field or property to be autowired:

public class MovieRecommender {

    @Autowired
    @Offline
    private MovieCatalog offlineCatalog;

    // ...
}

Now the bean definition only needs a qualifier 'type':

<bean class="example.SimpleMovieCatalog">
    <qualifier type="Offline"/>
    <!-- inject any dependencies required by this bean -->
</bean>

It is also possible to define custom qualifier annotations that accept named attributes in addition to or instead of the simple 'value' attribute. If multiple attribute values are then specified on a field or parameter to be autowired, a bean definition must match all such attribute values to be considered an autowire candidate. As an example, consider the following annotation definition:

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface MovieQualifier {

    String genre();
    
    Format format();
}

In this case Format is an enum:

public enum Format {
    
    VHS, DVD, BLURAY
}

The fields to be autowired are annotated with the custom qualifier and include values for both attributes: 'genre' and 'format'.

public class MovieRecommender {

    @Autowired
    @MovieQualifier(format=Format.VHS, genre="Action")
    private MovieCatalog actionVhsCatalog;

    @Autowired
    @MovieQualifier(format=Format.VHS, genre="Comedy")
    private MovieCatalog comedyVhsCatalog;

    @Autowired
    @MovieQualifier(format=Format.DVD, genre="Action")
    private MovieCatalog actionDvdCatalog;

    @Autowired
    @MovieQualifier(format=Format.BLURAY, genre="Comedy")
    private MovieCatalog comedyBluRayCatalog;
   
    // ...
}

Finally, the bean definitions should contain matching qualifier values. This example also demonstrates that bean meta attributes may be used instead of the <qualifier/> sub-elements. If available, the <qualifier/> and its attributes would take precedence, but the autowiring mechanism will fallback on the values provided within the <meta/> tags if no such qualifier is present (see the last 2 bean definitions below).

<?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:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:annotation-config/>

    <bean class="example.SimpleMovieCatalog">
        <qualifier type="MovieQualifier">
            <attribute key="format" value="VHS"/>
            <attribute key="genre" value="Action"/>
        </qualifier>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <qualifier type="MovieQualifier">
            <attribute key="format" value="VHS"/>
            <attribute key="genre" value="Comedy"/>
        </qualifier>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <meta key="format" value="DVD"/>
        <meta key="genre" value="Action"/>
        <!-- inject any dependencies required by this bean -->
    </bean>
    
    <bean class="example.SimpleMovieCatalog">
        <meta key="format" value="BLURAY"/>
        <meta key="genre" value="Comedy"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

</beans>

4.11.4 CustomAutowireConfigurer

The CustomAutowireConfigurer is a BeanFactoryPostProcessor that enables further customization of the autowiring process. Specifically, it allows you to register your own custom qualifier annotation types even if they are not themselves annotated with Spring's @Qualifier annotation.

<bean id="customAutowireConfigurer" class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
    <property name="customQualifierTypes">
        <set>
            <value>example.CustomQualifier</value>
        </set>
    </property>
</bean>

Note that the particular implementation of AutowireCandidateResolver that will be activated for the application context depends upon the Java version. If running on less than Java 5, the qualifier annotations are not supported, and therefore autowire candidates are solely determined by the 'autowire-candidate' value of each bean definition as well as any 'default-autowire-candidates' pattern(s) available on the <beans/> element. If running on Java 5 or greater, the presence of @Qualifier annotations or any custom annotations registered with the CustomAutowireConfigurer will also play a role.

Regardless of the Java version, the determination of a "primary" candidate (when multiple beans qualify as autowire candidates) is the same: if exactly one bean definition among the candidates has a 'primary' attribute set to 'true', it will be selected.

4.11.5 @Resource

Spring also supports injection using the JSR-250 @Resource annotation on fields or bean property setter methods. This is a common pattern found in Java EE 5 and Java 6 (e.g. in JSF 1.2 managed beans or JAX-WS 2.0 endpoints), which Spring supports for Spring-managed objects as well.

@Resource takes a 'name' attribute, and by default Spring will interpret that value as the bean name to be injected. In other words, it follows by-name semantics as demonstrated in this example:

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Resource(name="myMovieFinder")
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
}

If no name is specified explicitly, then the default name will be derived from the name of the field or setter method: In case of a field, it will simply be equivalent to the field name; in case of a setter method, it will be equivalent to the bean property name. So the following example is going to have the bean with name "movieFinder" injected into its setter method:

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Resource
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
}
[Note]Note

The name provided with the annotation will be resolved as a bean name by the BeanFactory of which the CommonAnnotationBeanPostProcessor is aware. Note that the names may be resolved via JNDI if Spring's SimpleJndiBeanFactory is configured explicitly. However, it is recommended to rely on the default behavior and simply use Spring's JNDI lookup capabilities to preserve the level of indirection.

Similar to @Autowired, @Resource may fall back to standard bean type matches (i.e. find a primary type match instead of a specific named bean) as well as resolve well-known "resolvable dependencies": the BeanFactory interface, the ApplicationContext interface, the ResourceLoader interface, the ApplicationEventPublisher interface and the MessageSource interface. Note that this only applies to @Resource usage with no explicit name specified!

So the following example will have its customerPreferenceDao field looking for a bean with name "customerPreferenceDao" first, then falling back to a primary type match for the type CustomerPreferenceDao. The "context" field will simply be injected based on the known resolvable dependency type ApplicationContext.

public class MovieRecommender {

    @Resource
    private CustomerPreferenceDao customerPreferenceDao;

    @Resource
    private ApplicationContext context;

    public MovieRecommender() {
    }

    // ...
}

4.11.6 @PostConstruct and @PreDestroy

The CommonAnnotationBeanPostProcessor not only recognizes the @Resource annotation but also the JSR-250 lifecycle annotations. Introduced in Spring 2.5, the support for these annotations offers yet another alternative to those described in the sections on initialization callbacks and destruction callbacks. Provided that the CommonAnnotationBeanPostProcessor is registered within the Spring ApplicationContext, a method carrying one of these annotations will be invoked at the same point in the lifecycle as the corresponding Spring lifecycle interface's method or explicitly declared callback method. In the example below, the cache will be pre-populated upon initialization and cleared upon destruction.

public class CachingMovieLister {

    @PostConstruct
    public void populateMovieCache() {
        // populates the movie cache upon initialization...
    }
    
    @PreDestroy
    public void clearMovieCache() {
        // clears the movie cache upon destruction...
    }
}
[Note]Note

For details regarding the effects of combining various lifecycle mechanisms, see Section 4.5.1.4, “Combining lifecycle mechanisms”.