Combining lifecycle mechanisms
As of Spring 2.5, you have three options for controlling bean lifecycle behavior: theInitializingBean
and DisposableBean
callback interfaces; custominit()
anddestroy()
methods; and the@PostConstruct
and @PreDestroy
annotations. You can combine these mechanisms to control a given bean.
![]() | Note |
---|---|
If multiple lifecycle mechanisms are configured for a bean, and each mechanism is configured with a different method name, then each configured method is executed in the order listed below. However, if the same method name is configured - for example, |
调用顺序
Multiple lifecycle mechanisms configured for the same bean, with different initialization methods, are called as follows:
-
Methods annotated with
@PostConstruct
-
afterPropertiesSet()
as defined by theInitializingBean
callback interface -
A custom configured
init()
method
Destroy methods are called in the same order:
-
Methods annotated with
@PreDestroy
-
destroy()
as defined by theDisposableBean
callback interface -
A custom configured
destroy()
method
Shutting down the Spring IoC container gracefully in non-web applications
![]() | Note |
---|---|
This section applies only to non-web applications. Spring's web-based |
If you are using Spring's IoC container in a non-web application environment; for example, in a rich client desktop environment; you register a shutdown hook with the JVM. Doing so ensures a graceful shutdown and calls the relevant destroy methods on your singleton beans so that all resources are released. Of course, you must still configure and implement these destroy callbacks correctly.
To register a shutdown hook, you call the registerShutdownHook()
method that is declared on theAbstractApplicationContext
class:
import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public final class Boot { public static void main(final String[] args) throws Exception { AbstractApplicationContext ctx = new ClassPathXmlApplicationContext(new String []{"beans.xml"}); // add a shutdown hook for the above context... ctx.registerShutdownHook(); // app runs here... // main method exits, hook is called prior to the app shutting down... } }
5.6.2 ApplicationContextAware
andBeanNameAware
When an ApplicationContext
creates a class that implements theorg.springframework.context.ApplicationContextAware
interface, the class is provided with a reference to thatApplicationContext
.
public interface ApplicationContextAware { void setApplicationContext(ApplicationContext applicationContext) throws BeansException; }
Thus beans can manipulate programmatically the ApplicationContext
that created them, through theApplicationContext
interface, or by casting the reference to a known subclass of this interface, such asConfigurableApplicationContext
, which exposes additional functionality. One use would be the programmatic retrieval of other beans. Sometimes this capability is useful; however, in general you should avoid it, because it couples the code to Spring and does not follow the Inversion of Control style, where collaborators are provided to beans as properties. Other methods of the ApplicationContext provide access to file resources, publishing application events, and accessing a MessageSource. These additional features are described in Section 5.14, “Additional Capabilities of the ApplicationContext
”
As of Spring 2.5, autowiring is another alternative to obtain reference to theApplicationContext
. The "traditional"constructor
andbyType
autowiring modes (as described inSection 5.4.5, “Autowiring collaborators”) can provide a dependency of typeApplicationContext
for a constructor argument or setter method parameter, respectively. For more flexibility, including the ability to autowire fields and multiple parameter methods, use the new annotation-based autowiring features. If you do, theApplicationContext
is autowired into a field, constructor argument, or method parameter that is expecting theApplicationContext
type if the field, constructor, or method in question carries the@Autowired
annotation. For more information, seeSection 5.9.2, “@Autowired
”.
When an ApplicationContext creates a class that implements the org.springframework.beans.factory.BeanNameAware
interface, the class is provided with a reference to the name defined in its associated object definition.
public interface BeanNameAware { void setBeanName(string name) throws BeansException; }
The callback is invoked after population of normal bean properties but before an initialization callback such asInitializingBean
safterPropertiesSet or a custom init-method.
5.7 Bean definition inheritance
A bean definition can contain a lot of configuration information, including constructor arguments, property values, and container-specific information such as initialization method, static factory method name, and so on. A child bean definition inherits configuration data from a parent definition. The child definition can override some values, or add others, as needed. Using parent and child bean definitions can save a lot of typing. Effectively, this is a form of templating.
If you work with an ApplicationContext
interface programmatically, child bean definitions are represented by theChildBeanDefinition
class. Most users do not work with them on this level, instead configuring bean definitions declaratively in something like theClassPathXmlApplicationContext
. When you use XML-based configuration metadata, you indicate a child bean definition by using theparent
attribute, specifying the parent bean as the value of this attribute.
<bean id="inheritedTestBean" abstract="true" class="org.springframework.beans.TestBean"> <property name="name" value="parent"/> <property name="age" value="1"/> </bean> <bean id="inheritsWithDifferentClass" class="org.springframework.beans.DerivedTestBean" parent="inheritedTestBean" init-method="initialize"> <property name="name" value="override"/> <!-- the age property value of 1 will be inherited from parent --> </bean>
A child bean definition uses the bean class from the parent definition if none is specified, but can also override it. In the latter case, the child bean class must be compatible with the parent, that is, it must accept the parent's property values.
A child bean definition inherits constructor argument values, property values, and method overrides from the parent, with the option to add new values. Any initialization method, destroy method, and/orstatic
factory method settings that you specify will override the corresponding parent settings.
The remaining settings are always taken from the child definition:depends on,autowire mode,dependency check,singleton,scope,lazy init.
The preceding example explicitly marks the parent bean definition as abstract by using theabstract
attribute. If the parent definition does not specify a class, explicitly marking the parent bean definition asabstract
is required, as follows:
<bean id="inheritedTestBeanWithoutClass" abstract="true"> <property name="name" value="parent"/> <property name="age" value="1"/> </bean> <bean id="inheritsWithClass" class="org.springframework.beans.DerivedTestBean" parent="inheritedTestBeanWithoutClass" init-method="initialize"> <property name="name" value="override"/> <!-- age will inherit the value of 1 from the parent bean definition--> </bean>
The parent bean cannot be instantiated on its own because it is incomplete, and it is also explicitly marked asabstract
. When a definition isabstract
like this, it is usable only as a pure template bean definition that serves as a parent definition for child definitions. Trying to use such anabstract
parent bean on its own, by referring to it as a ref property of another bean or doing an explicitgetBean()
call with the parent bean id, returns an error. Similarly, the container's internalpreInstantiateSingletons()
method ignores bean definitions that are defined as abstract.
![]() | Note |
---|---|
|
5.6.3 Other Aware
interfaces
Besides ApplicationContextAware
and BeanNameAware
discussed above, Spring offers a range of Aware
interfaces that allow beans to indicate to the container that they require a certaininfrastructure dependency. The most importantAware
interfaces are summarized below - as a general rule, the name is a good indication of the dependency type:
Table 5.4.
Aware
interfaces
Name | Injected Dependency | Explained in... |
---|---|---|
| Declaring | |
| Event publisher of the enclosing | Section 5.14, “Additional Capabilities of the |
| Class loader used to load the bean classes. | |
| Declaring | |
| Name of the declaring bean | |
| Resource adapter | |
| Defined weaver for processing class definition at load time | Section 9.8.4, “Load-time weaving with AspectJ in the Spring Framework” |
| Configured strategy for resolving messages (with support for parametrization and internationalization) | Section 5.14, “Additional Capabilities of the |
| Spring JMX notification publisher | |
| Current | |
| Current | |
| Configured loader for low-level access to resources | |
| Current | |
| Current |
Note again that usage of these interfaces ties your code to the Spring API and does not follow the Inversion of Control style. As such, they are recommended for infrastructure beans that require programmatic access to the container.
5.8.1 Customizing beans using a BeanPostProcessor
The BeanPostProcessor
interface defines callback methods that you can implement to provide your own (or override the container's default) instantiation logic, dependency-resolution logic, and so forth. If you want to implement some custom logic after the Spring container finishes instantiating, configuring, and initializing a bean, you can plug in one or more BeanPostProcessor
implementations.
You can configure multiple BeanPostProcessor
instances, and you can control the order in which theseBeanPostProcessor
s execute by setting theorder
property. You can set this property only if theBeanPostProcessor
implements theOrdered
interface; if you write your ownBeanPostProcessor
you should consider implementing theOrdered
interface too. For further details, consult the Javadoc for theBeanPostProcessor
andOrdered
interfaces. See also the note below onprogrammatic registration ofBeanPostProcessors
![]() | Note |
---|---|
To change the actual bean definition (i.e., the blueprint that defines the bean), you instead need to use a |
The org.springframework.beans.factory.config.BeanPostProcessor
interface consists of exactly two callback methods. When such a class is registered as a post-processor with the container, for each bean instance that is created by the container, the post-processor gets a callback from the container both before container initialization methods (such as InitializingBean'safterPropertiesSet() and any declared init method) are called as well asafter any bean initialization callbacks. The post-processor can take any action with the bean instance, including ignoring the callback completely. A bean post-processor typically checks for callback interfaces or may wrap a bean with a proxy. Some Spring AOP infrastructure classes are implemented as bean post-processors in order to provide proxy-wrapping logic.
An ApplicationContext
automatically detects any beans that are defined in the configuration metadata which implement theBeanPostProcessor
interface. TheApplicationContext
registers these beans as post-processors so that they can be called later upon bean creation. Bean post-processors can be deployed in the container just like any other beans.
5.8.2 Customizing configuration metadata with a BeanFactoryPostProcessor
The next extension point that we will look at is the org.springframework.beans.factory.config.BeanFactoryPostProcessor
. The semantics of this interface are similar to those of theBeanPostProcessor
, with one major difference:BeanFactoryPostProcessor
s operate on the bean configuration metadata; that is, the Spring IoC container allowsBeanFactoryPostProcessors
to read the configuration metadata and potentially change itbefore the container instantiates any beans other thanBeanFactoryPostProcessors
.
You can configure multiple BeanFactoryPostProcessors
, and you can control the order in which theseBeanFactoryPostProcessors
execute by setting theorder
property. However, you can only set this property if theBeanFactoryPostProcessor
implements theOrdered
interface. If you write your ownBeanFactoryPostProcessor
, you should consider implementing theOrdered
interface too. Consult the Javadoc for theBeanFactoryPostProcessor
andOrdered
interfaces for more details.
![]() | Note |
---|---|
If you want to change the actual bean instances (i.e., the objects that are created from the configuration metadata), then you instead need to use a Also, |
A bean factory post-processor is executed automatically when it is declared inside anApplicationContext
, in order to apply changes to the configuration metadata that define the container. Spring includes a number of predefined bean factory post-processors, such asPropertyOverrideConfigurer
andPropertyPlaceholderConfigurer
. A customBeanFactoryPostProcessor
can also be used, for example, to register custom property editors.
An ApplicationContext
automatically detects any beans that are deployed into it that implement theBeanFactoryPostProcessor
interface. It uses these beans as bean factory post-processors, at the appropriate time. You can deploy these post-processor beans as you would any other bean.
![]() | Note |
---|---|
As with |
Example: the PropertyPlaceholderConfigurer
You use the PropertyPlaceholderConfigurer
to externalize property values from a bean definition in a separate file using the standard JavaProperties
format. Doing so enables the person deploying an application to customize environment-specific properties such as database URLs and passwords, without the complexity or risk of modifying the main XML definition file or files for the container.
Consider the following XML-based configuration metadata fragment, where a DataSource
with placeholder values is defined. The example shows properties configured from an externalProperties
file. At runtime, aPropertyPlaceholderConfigurer
is applied to the metadata that will replace some properties of the DataSource. The values to replace are specified asplaceholders of the form ${property-name} which follows the Ant / log4j / JSP EL style.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations" value="classpath:com/foo/jdbc.properties"/> </bean> <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean>
The actual values come from another file in the standard Java Properties
format:
jdbc.driverClassName=org.hsqldb.jdbcDriver jdbc.url=jdbc:hsqldb:hsql://production:9002 jdbc.username=sa jdbc.password=root
Therefore, the string ${jdbc.username}
is replaced at runtime with the value 'sa', and the same applies for other placeholder values that match keys in the properties file. ThePropertyPlaceholderConfigurer
checks for placeholders in most properties and attributes of a bean definition. Furthermore, the placeholder prefix and suffix can be customized.
With the context
namespace introduced in Spring 2.5, it is possible to configure property placeholders with a dedicated configuration element. One or more locations can be provided as a comma-separated list in thelocation
attribute.
<context:property-placeholder location="classpath:com/foo/jdbc.properties"/>
The PropertyPlaceholderConfigurer
not only looks for properties in theProperties
file you specify. By default it also checks against the JavaSystem
properties if it cannot find a property in the specified properties files. You can customize this behavior by setting thesystemPropertiesMode
property of the configurer with one of the following three supported integer values:
-
never (0): Never check system properties
-
fallback (1): Check system properties if not resolvable in the specified properties files. This is the default.
-
override (2): Check system properties first, before trying the specified properties files. This allows system properties to override any other property source.
Consult the Javadoc for the PropertyPlaceholderConfigurer
for more information.
![]() | Class name substitution |
---|---|
You can use the <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <value>classpath:com/foo/strategy.properties</value> </property> <property name="properties"> <value>custom.strategy.class=com.foo.DefaultStrategy</value> </property> </bean> <bean id="serviceStrategy" class="${custom.strategy.class}"/> If the class cannot be resolved at runtime to a valid class, resolution of the bean fails when it is about to be created, which is during the |
Example: the PropertyOverrideConfigurer
The PropertyOverrideConfigurer
, another bean factory post-processor, resembles thePropertyPlaceholderConfigurer
, but unlike the latter, the original definitions can have default values or no values at all for bean properties. If an overridingProperties
file does not have an entry for a certain bean property, the default context definition is used.
Note that the bean definition is not aware of being overridden, so it is not immediately obvious from the XML definition file that the override configurer is being used. In case of multiplePropertyOverrideConfigurer
instances that define different values for the same bean property, the last one wins, due to the overriding mechanism.
Properties file configuration lines take this format:
beanName.property=value
For example:
dataSource.driverClassName=com.mysql.jdbc.Driver dataSource.url=jdbc:mysql:mydb
This example file can be used with a container definition that contains a bean calleddataSource, which hasdriver andurl properties.
Compound property names are also supported, as long as every component of the path except the final property being overridden is already non-null (presumably initialized by the constructors). In this example...
foo.fred.bob.sammy=123
... the sammy
property of the bob
property of the fred
property of the foo
bean is set to the scalar value 123
.
![]() | Note |
---|---|
Specified override values are always literal values; they are not translated into bean references. This convention also applies when the original value in the XML bean definition specifies a bean reference. |
With the context
namespace introduced in Spring 2.5, it is possible to configure property overriding with a dedicated configuration element:
<context:property-override location="classpath:override.properties"/>
5.8.3 Customizing instantiation logic with a FactoryBean
Implement the org.springframework.beans.factory.FactoryBean
interface for objects thatare themselves factories.
The FactoryBean
interface is a point of pluggability into the Spring IoC container's instantiation logic. If you have complex initialization code that is better expressed in Java as opposed to a (potentially) verbose amount of XML, you can create your own FactoryBean
, write the complex initialization inside that class, and then plug your customFactoryBean
into the container.
The FactoryBean
interface provides three methods:
-
Object getObject()
: returns an instance of the object this factory creates. The instance can possibly be shared, depending on whether this factory returns singletons or prototypes. -
boolean isSingleton()
: returnstrue
if thisFactoryBean
returns singletons,false
otherwise. -
Class getObjectType()
: returns the object type returned by thegetObject()
method ornull
if the type is not known in advance.
The FactoryBean
concept and interface is used in a number of places within the Spring Framework; more than 50 implementations of theFactoryBean
interface ship with Spring itself.
When you need to ask a container for an actual FactoryBean
instance itself instead of the bean it produces, preface the bean's id with the ampersand symbol (&
) when calling thegetBean()
method of the ApplicationContext
. So for a givenFactoryBean
with an id ofmyBean
, invokinggetBean("myBean")
on the container returns the product of theFactoryBean
; whereas, invokinggetBean("&myBean")
returns theFactoryBean
instance itself.
5.9 Annotation-based container configuration
An alternative to XML setups is provided by annotation-based configuration which rely on the bytecode metadata for wiring up components instead of angle-bracket declarations. Instead of using XML to describe a bean wiring, the developer moves the configuration into the component class itself by using annotations on the relevant class, method, or field declaration. As mentioned inthe section called “Example: The RequiredAnnotationBeanPostProcessor
”, using aBeanPostProcessor
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. Spring 2.5 made it possible to follow that same general approach to drive Spring's dependency injection. Essentially, the@Autowired
annotation provides the same capabilities as described inSection 5.4.5, “Autowiring collaborators” but with more fine-grained control and wider applicability. Spring 2.5 also added support for JSR-250 annotations such as@PostConstruct
, and@PreDestroy
. Spring 3.0 added support for JSR-330 (Dependency Injection for Java) annotations contained in the javax.inject package such as@Inject
and@Named
. Details about those annotations can be found in therelevant section.
![]() | Note |
---|---|
Annotation injection is performed before XML injection, thus the latter configuration will override the former for properties wired through both approaches. |
As always, you can register them 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 thecontext
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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config/> </beans>
(The implicitly registered post-processors include AutowiredAnnotationBeanPostProcessor
, CommonAnnotationBeanPostProcessor
, PersistenceAnnotationBeanPostProcessor
, as well as the aforementionedRequiredAnnotationBeanPostProcessor
.)
![]() | Note |
---|---|
|
5.9.2 @Autowired
As expected, you can apply the @Autowired
annotation to "traditional" setter methods:
public class SimpleMovieLister { private MovieFinder movieFinder; @Autowired public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } // ... }
![]() | Note |
---|---|
JSR 330's @Inject annotation can be used in place of Spring's |
You can also apply the annotation 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; } // ... }
You can apply @Autowired
to 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 theApplicationContext
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 can 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 fails whenever zero candidate beans are available; the default behavior is to treat annotated methods, constructors, and fields as indicatingrequired 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 |
---|---|
Only one annotated constructor per-class can be marked asrequired, but multiple non-required constructors can be annotated. In that case, each is considered among the candidates and Spring uses thegreediest constructor whose dependencies can be satisfied, that is the constructor that has the largest number of arguments.
|
You can also use @Autowired
for interfaces that are well-known resolvable dependencies:BeanFactory
,ApplicationContext
,Environment
, ResourceLoader
,ApplicationEventPublisher
, and MessageSource
. These interfaces and their extended interfaces, such asConfigurableApplicationContext
orResourcePatternResolver
, are automatically resolved, with no special setup necessary.
public class MovieRecommender { @Autowired private ApplicationContext context; public MovieRecommender() { } // ... }
![]() | Note |
---|---|
|
建议使用@Resource,如果要使用@Autowired,最好和@Qualifier一起使用
![]() | Tip |
---|---|
If you intend to express annotation-driven injection by name, do not primarily use As a specific consequence of this semantic difference, beans that are themselves defined as a collection or map type cannot be injected through
|
5.9.5 @Resource
@Resource不指定name,则默认使用变量名注入,如果指定了name,则用指定name的bean注入。
Spring also supports injection using the JSR-250 @Resource
annotation on fields or bean property setter methods. This is a common pattern in Java EE 5 and 6, for example in JSF 1.2 managed beans or JAX-WS 2.0 endpoints. Spring supports this pattern for Spring-managed objects as well.
@Resource
takes a name attribute, and by default Spring interprets that value as the bean name to be injected. In other words, it followsby-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, the default name is derived from the field name or setter method. In case of a field, it takes the field name; in case of a setter method, it takes 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 |
---|---|
The name provided with the annotation is resolved as a bean name by the |
In the exclusive case of @Resource
usage with no explicit name specified, and similar to@Autowired
, @Resource
finds a primary type match instead of a specific named bean and resolves well-known resolvable dependencies: theBeanFactory
, ApplicationContext,
ResourceLoader, ApplicationEventPublisher
, andMessageSource
interfaces.
Thus in the following example, the customerPreferenceDao
field first looks for a bean named customerPreferenceDao, then falls back to a primary type match for the typeCustomerPreferenceDao
. The "context" field is injected based on the known resolvable dependency typeApplicationContext
.
public class MovieRecommender { @Resource private CustomerPreferenceDao customerPreferenceDao; @Resource private ApplicationContext context; public MovieRecommender() { } // ... }
5.9.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 initialization callbacks and destruction callbacks. Provided that the CommonAnnotationBeanPostProcessor
is registered within the Spring ApplicationContext
, a method carrying one of these annotations is invoked at the same point in the lifecycle as the corresponding Spring lifecycle interface 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... } }