Spring Beans - Lifecycle

Spring bean lifecycle

https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-lifecycle

Lets look at the following topics:

  1. Bean life cycle stages, initialization and destruction call back methods.
  2. How to customize the bean life cycle events using XML configuration?
  3. How to customize the bean life cycle events using Java annotation configuration?

1. What is Life Cycle of a Bean?

A Spring bean needs to be instantiated when the container starts, based on Java or XML bean definition. The framework may also be required to perform some pre and post-initialization steps to get the bean into a usable state.

After that, when the bean is no longer required, it will be removed from the IoC container. Like the initialization phase, the Spring framework may need to perform pre-and post-destruction steps to free the other system resources.

Spring bean factory is responsible for managing the life cycle callbacks of the beans which are created in the spring containers. Spring bean factory is responsible for managing the life cycle of beans created through spring containers.

1.1. Life Cycle Callback Methods

Spring bean factory controls the creation and destruction of beans. In order to let developers execute some custom code during bean creation or destruction, the bean factory provides certain callback methods. The callback methods can be categorized broadly into two groups:

  1. Post-initialization callback methods

  2. Pre-destruction callback methods

2. How to Customize the Bean Life Cycle

Spring framework provides the following four ways for controlling life cycle events of a bean:

  1. InitializingBean and DisposableBean callback interfaces
  2. Aware interfaces for specific behavior
  3. Custom init() and destroy() methods in bean configuration file
  4. @PostConstruct and @PreDestroy annotations

Let’s learn about each way in some detail.

2.1. InitializingBean and DisposableBean Interfaces

The org.springframework.beans.factory.InitializingBean interface allows a bean to perform initialization work after all the necessary properties on the bean have been set by the container.

The InitializingBean interface specifies a single method:

void afterPropertiesSet() throws Exception;

The afterPropertiesSet() method is not a preferable way to initialize the bean because it tightly couples the bean class with the spring container. A better approach is to use init-method attribute in bean definition in applicationContext.xml.

Similarly, implementing the org.springframework.beans.factory.DisposableBean interface allows a bean to get a callback before the Spring container destroys the bean.

The DisposableBean interface specifies a single method:

void destroy() throws Exception;

A sample bean implementing the above interfaces would look like this:

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class DemoBean implements InitializingBean, DisposableBean
{
        //Other bean attributes and methods

        @Override
        public void afterPropertiesSet() throws Exception
        {
                //Bean initialization code
        }

        @Override
        public void destroy() throws Exception
        {
                //Bean destruction code
        }
}

2.2. *Aware Interfaces to Add Specific Behavior

Spring offers a range of interfaces that allow the beans to indicate to the container that they require a particular infrastructure dependency.

Each of these Aware interfaces will require us to implement a method to inject the dependency in the bean.

We can summarize these interfaces as :

Aware interface Method to override Purpose
ApplicationContextAware void setApplicationContext (ApplicationContext applicationContext) throws BeansException; Interface to be implemented by any object that wishes to be notified of the ApplicationContext that it runs in.
ApplicationEventPublisherAware void setApplicationEventPublisher (ApplicationEventPublisher applicationEventPublisher); Set the ApplicationEventPublisher that this object runs in.
BeanClassLoaderAware void setBeanClassLoader (ClassLoader classLoader); Callback that supplies the bean class loader to a bean instance.
BeanFactoryAware void setBeanFactory (BeanFactory beanFactory) throws BeansException; Callback that supplies the owning factory to a bean instance.
BeanNameAware void setBeanName(String name); Set the name of the bean in the bean factory that created this bean.
BootstrapContextAware void setBootstrapContext (BootstrapContext bootstrapContext); Set the BootstrapContext that this object runs in.
LoadTimeWeaverAware void setLoadTimeWeaver (LoadTimeWeaver loadTimeWeaver); Set the LoadTimeWeaver of this object’s containing ApplicationContext.
MessageSourceAware void setMessageSource (MessageSource messageSource); Set the MessageSource that this object runs in.
NotificationPublisherAware void setNotificationPublisher (NotificationPublisher notificationPublisher); Set the NotificationPublisher instance for the current managed resource instance.
PortletConfigAware void setPortletConfig (PortletConfig portletConfig); Set the PortletConfig this object runs in.
PortletContextAware void setPortletContext (PortletContext portletContext); Set the PortletContext that this object runs in.
ResourceLoaderAware void setResourceLoader (ResourceLoader resourceLoader); Set the ResourceLoader that this object runs in.
ServletConfigAware void setServletConfig (ServletConfig servletConfig); Set the ServletConfig that this object runs in.
ServletContextAware void setServletContext (ServletContext servletContext); Set the ServletContext that this object runs in.

Java program to show the use of Aware interfaces.

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class DemoBean implements ApplicationContextAware
{

        private ApplicationContext ctx;

        @Override
        public void setApplicationContext(ApplicationContext ctx)
                        throws BeansException {
                this.ctx = ctx;
        }

        //Use the context in other bean methods
}

2.3. Custom init() and destroy() Methods

We can add the default init() and destroy() methods in two ways:

  1. Local definitions applicable to a single bean
  2. Global definitions applicable to all beans defined in whole beans context
  • 2.3.1. Local definitions

    The local init() and destroy() methods are configured as in the given example.

    <beans>
    
        <bean id="demoBean" class="com.howtodoinjava.task.DemoBean"
                        init-method="customInit"
                        destroy-method="customDestroy"></bean>
    
    </beans>
    
  • 2.3.2. Global definitions

    The container will invoke the global methods for all bean definitions given under <beans> tag. Global overrides are helpful when we have a pattern of defining common method names such as init() and destroy() for all the beans consistently.

    This feature helps us in not mentioning the init and destroy method names for all beans independently.

    <beans default-init-method="customInit" default-destroy-method="customDestroy">
    
            <bean id="demoBean" class="com.howtodoinjava.task.DemoBean"></bean>
    
    </beans>
    

    Based on the above local or global overrides, we must write the customInit() and customDestroy() methods in the bean classes as below example.

    public class DemoBean
    {
            public void customInit()
            {
                    System.out.println("Method customInit() invoked...");
            }
    
            public void customDestroy()
            {
                    System.out.println("Method customDestroy() invoked...");
            }
    }
    

2.4. @PostConstruct and @PreDestroy Annotations

From Spring 2.5 onwards, we can use the @PostConstruct and @PreDestroy annotations for specifying the bean life cycle methods.

  1. @PostConstruct annotated method will be invoked after the bean has been constructed using default constructor and just before it’s instance is returned to requesting object.
  2. @PreDestroy annotated method is invoked just before the bean is about be destroyed inside bean container.

Java program to show usage of annotation configuration to control using annotations.

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class DemoBean
{
        @PostConstruct
        public void customInit()
        {
                System.out.println("Method customInit() invoked...");
        }

        @PreDestroy
        public void customDestroy()
        {
                System.out.println("Method customDestroy() invoked...");
        }
}

Reading material

KNOWLEDGE GAP - LEARN MORE, IMPLEMENT THIS

  1. https://www.digitalocean.com/community/tutorials/spring-bean-life-cycle
  2. https://howtodoinjava.com/spring-core/spring-bean-life-cycle/
  3. https://www.baeldung.com/spring-postconstruct-predestroy

Links to this note