To interact with the container bean lifecycle management mechanism, you can implement the
InitializingBean
and DisposableBean
interfaces in Spring. The container calls afterPropertiesSet()
on the first and destroy()
on the second so that the bean can perform certain actions when initializing
and destroying your beans.
The @PostConstruct
and @PreDestroy
annotations
standardized by JSR-250 are generally considered the best practice for getting lifecycle callbacks in modern Spring
application. Using these annotations means that your beans are not bound to Spring-specific interfaces.
If you don't want to use JSR-250 annotations but still want to eliminate coupling, consider the
init-method
and destroy-method
bean definition metadata.
Internally, the
Spring Framework uses BeanPostProcessor
implementations to handle any callback interfaces it can find
and call the appropriate methods. If you need special functions or other lifecycle logic that Spring doesn't offer
by default, you can implement BeanPostProcessor
yourself.
In addition to initialization and
destruction callbacks, objects managed by Spring may also implement the Lifecycle
interface so that
these objects can participate in the startup and termination process defined by the container's own lifecycle.
Lifecycle callback interfaces are described in this section.
Initialization callbacks
The org.springframework.beans.factory.InitializingBean
interface allows the bean to perform initialization after the container has set all the bean's required properties.
The InitializingBean
interface defines a single method:
void afterPropertiesSet() throws Exception;
We do not recommend using the InitializingBean
interface as it is redundant links the code to
Spring. As an alternative, we suggest using the @PostConstruct
annotation or specifying the POJO's
initialization method. For XML-based configuration metadata, you can use the init-method
attribute to
specify the name of a method that returns void and has no arguments. In Java configuration, you can use the initMethod
attribute on @Bean
. Consider the following example:
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean {
public void init() {
// do some initialization
}
}
class ExampleBean {
fun init() {
// do some initialization
}
}
The previous example produces almost exactly the same result as the following example (consisting of two listings):
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements InitializingBean {
@Override
public void afterPropertiesSet() {
// do some initialization
}
}
class AnotherExampleBean : InitializingBean {
override fun afterPropertiesSet() {
// do some initialization
}
}
However, in the first of the two previous examples, the code is not associated with Spring.
Destruction callbacks
The org.springframework.beans.factory.DisposableBean
interface
implementation allows a bean to receive a callback when the container containing it is destroyed . The DisposableBean
interface defines a single method:
void destroy() throws Exception;
We do not recommend using the DisposableBean
callback interface because it unnecessarily couples
the code to Spring. As an alternative, we suggest using the @PreDestroy
annotation or specifying a
generic method that is supported by bean definitions. When using XML-based configuration metadata, you can use the
destroy-method
attribute on <bean/>
. In Java configuration, you can use the destroyMethod
attribute on @Bean
. Consider the following definition:
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
public class ExampleBean {
public void cleanup() {
// do some cleanup work (e.g. freeing connection pools)
}
}
class ExampleBean {
fun cleanup() {
// do some cleanup work (e.g. free up connection pools)
}
}
The previous definition produces almost exactly the same result as the following:
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements DisposableBean {
@Override
public void destroy() {
// do some destruction work (e.g. freeing connection pools)
}
}
class AnotherExampleBean : DisposableBean {
override fun destroy() {
// do some destruction work (e.g. freeing connection pools)
}
}
However, the first of the two previous definitions does not associate code with Spring.
destroy-method
attribute of the <bean>
element to a special (inferred)
value that instructs Spring to automatically detect the public close
or shutdown
method for a specific bean class. (So any class that implements java.lang.AutoCloseable
or java.io.Closeable
will do). You can also set this special (inferred)
value to the
default-destroy-method
attribute of the <beans>
element to apply this logic to
the entire set of beans. Note that this is the default logic when using a Java configuration.
Default initialization and destruction methods
If you are writing callbacks to initialization and
destruction methods that do not use Spring-specific ones callback interfaces InitializingBean
and
DisposableBean
, then you typically write methods with names like init()
, initialize()
,
dispose()
and so on. Ideally, the names of such lifecycle callback methods are standardized
across the project so that all developers use the same method names, ensuring consistency.
You can configure
the Spring container to "look up" the names of the initialization and callback methods call destruction for each
bean, if such names are assigned to them. This means that you, as an application developer, can write your
application classes and use the initialization callback called init()
without having to configure the
init-method="init"
attribute for each bean definition. The Spring IoC container calls this method when
the bean is created (and according to the standard lifecycle callback contract). This function also provides a
consistent naming convention for initialization and destruction callbacks.
Assume that your initialization
callback methods are named init()
and your destruction callback methods are destroy()
.
Then your class will be similar to 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.");
}
}
}
class DefaultBlogService : BlogService {
private var blogDao: BlogDao? = null
// this is (unsurprisingly) the initialization callback method
fun init() {
if (blogDao == null) {
throw IllegalStateException("The [blogDao] property must be set.")
}
}
}
You can then use this class in beans similar to the following:
<beans default-init-method="init">
<bean id="blogService" class="com.something.DefaultBlogService">
<property name="blogDao" ref="blogDao" />
</bean>
</beans>
The presence of the default-init-method
attribute in the top-level element attribute <beans/>
causes the Spring IoC container to recognize the bean class's init
method as an
initialization method callback. When a bean is created and linked, if the bean class contains such a method, then it
is invoked at the appropriate time.
You can configure destroy method callbacks in a similar way (meaning in
XML), using the default attribute -destroy-method
in the top-level <beans/>
element.
In cases where existing bean classes already contain callback methods that are not named in By convention, you
can override the default by specifying (meaning XML) the name of the method using the init-method
and
destroy-method
attributes of the <bean/>
.
The Spring container ensures that
the configured initialization callback is called immediately after the bean has received all dependencies. So the
initialization callback is called to reference the raw bean, which means AOP hooks etc. have not yet been applied to
the bean. First, the entire target bean is created, and then an AOP proxy (for example) is applied with its chain of
interceptors. If the target bean and proxy are defined separately, your code can even interact with the raw target
bean without going through the proxy. Therefore, it would be inconsistent to apply interceptors to the
init
method, since then the target bean's lifecycle would be tied to its proxies or interceptors,
resulting in strange semantics when your code interacts directly with the raw target bean.
Combining lifecycle mechanisms
Starting with Spring 2.5, there are three options for managing the bean's lifecycle logic:
Interfaces callbacks
InitializingBean
andDisposableBean
Special methods
init()
anddestroy ()
Annotations
@PostConstruct
and@PreDestroy
. You can combine these mechanisms to control a specific bean.
init()
for the initialization
method - for more than one of these lifecycle mechanisms, that method is run once, as explained in the previous
section.
Multiple lifecycle mechanisms configured for the same bean, with different initialization methods, are invoked as follows:
Methods annotated with
@ PostConstruct
callback interfaceafterPropertiesSet(),
as defined by theInitializingBean
Specially configured method
init()
Destruction methods are called in the same order:
Methods annotated with
@PreDestroy
destroy(),
as defined by the callback interfaceDisposableBean
Special configured method
destroy()
Startup and termination callbacks
The Lifecycle
interface defines basic methods for any object that has its own lifecycle requirements
(for example, starting and stopping some background process):
public interface Lifecycle {
void start();
void stop();
boolean isRunning();
}
Any object managed by Spring can implement the Lifecycle
interface. Then, when the ApplicationContext
itself receives start and stop signals (for example, for a runtime stop/restart script), it cascades those calls
across all Lifecycle
implementations defined in that context . It does this by delegating to LifecycleProcessor
,
as shown in the following listing:
public interface LifecycleProcessor extends Lifecycle {
void onRefresh();
void onClose();
}
Note that LifecycleProcessor
is itself an extension of the Lifecycle
interface. It also
adds two other methods to respond to updating and closing the context.
Note that the familiar org.springframework.context interface
.Lifecycle
is a common contract for explicit start and stop notifications and does not automatically
start when the context is updated. For finer control over the automatic startup of a specific bean (including
startup phases), consider implementing org.springframework.context.SmartLifecycle
.
Also note that stop notifications are not guaranteed come before destruction. During a normal shutdown, all
Lifecycle
beans are first notified of the shutdown before the general kill callbacks are
propagated. However, in the case of a hot refresh, during the lifetime of the context or when refresh
attempts are stopped, only the destroy methods are called.
The order of startup and shutdown calls can be important. If a dependencies-on relationship exists between any
two objects, then the dependent party starts after its dependency and stops before its dependency. However,
sometimes direct relationships are unknown. All you can know is that objects of a certain type must run before
objects of another type. In these cases, the SmartLifecycle
interface defines a different option,
namely the getPhase()
method defined in its Phased
superinterface. The following
listing shows the definition of the Phased
interface:
public interface Phased {
int getPhase();
}
The following listing shows the definition of the SmartLifecycle
interface:
public interface SmartLifecycle extends Lifecycle, Phased {
boolean isAutoStartup();
void stop(Runnable callback);
}
When starting, objects with the smallest phase are launched first. When stopping, proceed in reverse order.
Therefore, an object that implements SmartLifecycle
and whose getPhase()
method
returns Integer.MIN_VALUE
will be one of the first to run and the last one to run. who will stop.
At the other end of the spectrum, the Integer.MAX_VALUE
phase value indicates that the object
should start last and be stopped first (probably because it depends on other running processes). When
considering the value of phase, it is also important to know that the default phase for any "regular" Lifecycle
object that does not implement SmartLifecycle
is 0
. Therefore, any negative phase
value indicates that the object should start before (and stop after) these standard components. The converse is
true for any positive phase value.
The stopping method defined by SmartLifecycle
accepts a callback. Any implementation must initiate
the run()
method of this callback after that implementation's shutdown process has completed. This
ensures asynchronous shutdown when needed because the default implementation of the
LifecycleProcessor
interface, DefaultLifecycleProcessor
, waits for a value-specified
timeout until a group of objects in each phase initiates this callback. The default timeout for each phase is 30
seconds. You can override the default lifecycle processor instance by defining a bean named
lifecycleProcessor
in the context. If you only need to change the timeout, just define the following:
<bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
<!-- timeout value in milliseconds -->
<property name="timeoutPerShutdownPhase" value="10000"/>
</bean>
As mentioned earlier, the LifecycleProcessor
interface defines callback methods for updating and
closing the context. The latter controls the shutdown process as if stop()
had been called
explicitly, but this occurs when the context is closed. The refresh callback, on the other hand, allows you to
take advantage of another feature of SmartLifecycle
beans. If the context is updated (after all
object instances have been created and initialized), this callback is fired. At this point, the default
lifecycle processor checks the Boolean value returned by the isAutoStartup()
method of each SmartLifecycle
object. If true
, then this object starts at that moment, rather than waiting for an explicit call
to the context's start()
method or its own method (unlike updating the context, starting the
context does not occurs automatically in the standard implementation of the context). The phase
value and any "depends-on" relationships determine the startup order, as described earlier.
Gradually shutting down the Spring IoC container in non-Web applications
This section applies to non-web applications only. ApplicationContext
implementations for web applications in the Spring framework contain code to gracefully shut down the Spring IoC
container when the corresponding web application exits.
If you are using IoC- Spring container in a non-web application environment (for example, a rich desktop client environment), register a shutdown hook with the JVM. This way you can ensure that your singleton beans are shut down gracefully and the appropriate destruction methods are invoked to free up all resources. You still need to properly configure and implement these kill callbacks.
To register a shutdown hook, call the registerShutdownHook()
method, which is declared in the ConfigurableApplicationContext
interface , as shown in the following example:
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public final class Boot {
public static void main(final String[] args) throws Exception {
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
// add a shutdown hook for the above context...
ctx.registerShutdownHook();
// the application starts...
// the main method ends, the interceptor is called before the application exits...
}
}
import org.springframework.context.support.ClassPathXmlApplicationContext
fun main() {
val ctx = ClassPathXmlApplicationContext("beans.xml")
// add a shutdown hook for the above context...
ctx.registerShutdownHook()
// application runs...
// the main method ends, the interceptor is called before the application exits...
}