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"/>
Java

public class ExampleBean {
    public void init() {
        // do some initialization
    }
}
Kotlin

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"/>
Java

public class AnotherExampleBean implements InitializingBean {
    @Override
    public void afterPropertiesSet() {
        // do some initialization
    }
}
Kotlin

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"/>
Java

public class ExampleBean {
    public void cleanup() {
        // do some cleanup work (e.g. freeing connection pools)
    }
}
Kotlin

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"/>
Java

public class AnotherExampleBean implements DisposableBean {
    @Override
    public void destroy() {
        // do some destruction work (e.g. freeing connection pools)
    }
}
Kotlin

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.

You You can set the 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:

Java

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.");
        }
    }
}
Kotlin

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 and DisposableBean

  • Special methods init() and destroy ()

  • Annotations @PostConstruct and @PreDestroy. You can combine these mechanisms to control a specific bean.

If multiple lifecycle mechanisms are configured for a bean, and for each If the mechanism is configured with its own method name, then each configured method runs in the order specified after this note. However, if the same method name is configured - for example, 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:

  1. Methods annotated with @ PostConstruct

  2. afterPropertiesSet(), as defined by the InitializingBean

    callback interface
  3. Specially configured method init()

Destruction methods are called in the same order:

  1. Methods annotated with @PreDestroy

  2. destroy(), as defined by the callback interface DisposableBean

  3. 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:

Java

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...
    }
}
Kotlin
        
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...
}