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...
}
GO TO FULL VERSION