To interact with the container's management of the bean lifecycle,
you can implement the Spring
InitializingBean
and
DisposableBean
interfaces. The container
calls afterPropertiesSet()
for the former and
destroy()
for the latter to allow the bean to
perform certain actions upon initialization and destruction of your
beans. You can also achieve the same integration with the container
without coupling your classes to Spring interfaces though the use of
init-method and destroy method object definition metadata.
Internally, the Spring Framework uses
BeanPostProcessor
implementations to
process any callback interfaces it can find and call the appropriate
methods. If you need custom features or other lifecycle behavior Spring
does not offer out-of-the-box, you can implement a
BeanPostProcessor
yourself. For more
information, see Section 3.8, “Container extension points”.
The lifecycle callback interfaces are described in this section.
The
org.springframework.beans.factory.InitializingBean
interface allows a bean to perform initialization work after all
necessary properties on the bean have been set by the container. The
InitializingBean
interface specifies a
single method:
void afterPropertiesSet() throws Exception;
It is recommended that you do not use the
InitializingBean
interface because it
unnecessarily couples the code to Spring. Alternatively, specify a
POJO initialization method. In the case of XML-based configuration
metadata, you use the init-method
attribute to
specify the name of the method that has a void no-argument signature.
For example, the following definition:
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean { public void init() { // do some initialization work } }
...is exactly the same as...
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements InitializingBean { public void afterPropertiesSet() { // do some initialization work } }
... but does not couple the code to Spring.
Implementing the
org.springframework.beans.factory.DisposableBean
interface allows a bean to get a callback when the container
containing it is destroyed. The
DisposableBean
interface specifies a
single method:
void destroy() throws Exception;
It is recommended that you do not use the
DisposableBean
callback interface
because it unnecessarily couples the code to Spring. Alternatively,
specify a generic method that is supported by bean definitions. With
XML-based configuration metadata, you use the
destroy-method
attribute on the
<bean/>
. For example, the following
definition:
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
public class ExampleBean { public void cleanup() { // do some destruction work (like releasing pooled connections) } }
...is exactly the same as...
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements DisposableBean { public void destroy() { // do some destruction work (like releasing pooled connections) } }
... but does not couple the code to Spring.
When you write initialization and destroy method callbacks that
do not use the Spring-specific
InitializingBean
and
DisposableBean
callback interfaces, you
typically write methods with names such as init()
,
initialize()
, dispose()
, and so
on. Ideally, the names of such lifecycle callback methods are
standardized across a project so that all developers use the same
method names and ensure consistency.
You can configure the Spring container to
look
for named initialization and destroy callback
method names on every bean. This means that you,
as an application developer, can write your application classes and
use an initialization callback called init()
,
without having to configure an init-method="init"
attribute with each bean definition. The Spring IoC container calls
that method when the bean is created (and in accordance with the
standard lifecycle callback contract described previously). This
feature also enforces a consistent naming convention for
initialization and destroy method callbacks.
Suppose that your initialization callback methods are named
init()
and destroy callback methods are named
destroy()
. Your class will resemble the class in
the following example.
public class DefaultBlogService implements BlogService { private BlogDao blogDao; public void setBlogDao(BlogDao blogDao) { this.blogDao = blogDao; } // this is (unsurprisingly) the initialization callback method public void init() { if (this.blogDao == null) { throw new IllegalStateException("The [blogDao] property must be set."); } } }
<beans default-init-method="init"> <bean id="blogService" class="com.foo.DefaultBlogService"> <property name="blogDao" ref="blogDao" /> </bean> </beans>
The presence of the default-init-method
attribute on the top-level <beans/>
element
attribute causes the Spring IoC container to recognize a method called
init
on beans as the initialization method
callback. When a bean is created and assembled, if the beans class has
such a method, it is invoked at the appropriate time.
You configure destroy method callbacks similarly (in XML, that
is) by using the default-destroy-method
attribute
on the top-level <beans/>
element.
Where existing bean classes already have callback methods that are named at variance with the convention, you can override the default by specifying (in XML, that is) the method name using the init-method and destroy-method attributes on the <bean/> itself.
The Spring container guarantees that a configured initialization callback is called immediately after a bean is supplied with all dependencies. Thus the initialization callback is called on the raw bean reference, which means that AOP interceptors and so forth are not yet applied to the bean. A target bean is fully created first, then an AOP proxy (for example) with its interceptor chain is applied. If the target bean and the proxy are defined separately, your code can even interact with the raw target bean, bypassing the proxy. Hence, it would be inconsistent to apply the interceptors to the init method, because doing so would couple the lifecycle of the target bean with its proxy/interceptors and leave strange semantics when your code interacts directly to the raw target bean.
As of Spring 2.5, you have three options for controlling bean
lifecycle behavior: the InitializingBean
and DisposableBean
callback interfaces; custom init()
and
destroy()
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 lifestyle mechanisms configured for the same bean, with different initialization methods, are called as follows:
Methods annotated with
@PostConstruct
afterPropertiesSet()
as defined by the
InitializingBean
callback
interface
A custom configured init()
method
Destroy methods are called in the same order:
Methods annotated with
@PreDestroy
destroy()
as defined by the
DisposableBean
callback
interface
A custom configured destroy()
method
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 the AbstractApplicationContext
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... } }
When an ApplicationContext
creates
a class that implements the
org.springframework.contxt.ApplicationContextAware
interface, the class is provided with a reference to that
ApplicationContext
.
public interface ApplicationContextAware { void setApplicationContext(ApplicationContext applicationContext) throws BeansException; }
Thus beans can manipulate programmatically the
ApplicationContext
that created them,
through the ApplicationContext
interface,
or by casting the reference to a known subclass of this interface, such
as ConfigurableApplicationContext
, 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 3.13, “Additional Capabilities of the
ApplicationContext”
As of Spring 2.5, autowiring is another alternative to obtain
reference to the ApplicationContext
. The
"traditional" constructor
and
byType
autowiring modes (as described in Section 3.4.5, “Autowiring collaborators”) can provide a dependency of type
ApplicationContext
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, the
ApplicationFactory
is autowired into a
field, constructor argument, or method parameter that is expecting the
BeanFactory
type if the field,
constructor, or method in question carries the
@Autowired
annotation. For more
information, see Section 3.9.2, “@Autowired and @Inject”.
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 as
InitializingBean
s
afterPropertiesSet or a custom init-method.