Thursday, June 9, 2022

Spring Bean Life Cycle

Spring bean life cycle is quite elaborate and provides many callback methods to customize the nature of the bean.

On the basis of functionality provided by these callback methods with in the Spring bean lifecycle, you can categorize these callback methods into two categories-

  1. Callback methods called at the time of instantiating a bean.
  2. Callback methods called at the time of disposing a bean.

Spring bean life cycle callback methods

Within the span of instantiating and later disposing a bean, Spring framework provides the following ways for implementing bean life cycle methods.

  1. InitializingBean and DisposableBean interfaces which you can implement and provide implementation of afterPropertiesSet() method for the former (InitializingBean) and destroy() method for the latter (DisposableBean) to allow the bean to perform certain actions upon initialization and destruction of your beans.
  2. There are other ways to provide the functionality as provided by InitializingBean and DisposableBean interfaces. You can use @PostConstruct and @PreDestroy annotations to allow the bean to perform certain actions upon initialization and destruction of your beans respectively.

  3. If you don't want to use the JSR-250 annotations you can use init-method and destroy-method attributes with in your configuration file to define custom init() and destroy() methods.

    According to Spring docs it is better to use these annotations or init-method and destroy-method for receiving lifecycle callbacks because using them means your beans are not coupled to Spring specific interfaces.

  4. Other aware interfaces like ApplicationContextAware And BeanNameAware.

You can also combine these options to control a given bean.

bean lifecycle in Spring

Spring bean life cycle methods execution order

If multiple life cycle 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.

For intialization methods

  • 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

InitializingBean and DisposableBean callback interfaces

InitializingBean interface has a single method afterPropertiesSet() which can be implemented to provide any initialization related code.

DisposableBean interface has a single method destroy() which can be implemented to provide any cleanup code at the time of the destruction of the bean.

Spring bean life cycle example - InitializingBean and DisposableBean

Let's see a Spring bean life cycle example where we have PayServiceImpl bean which will implement InitializingBean and DisposableBean interfaces and provide implementation for the afterPropertiesSet() and destroy() methods.

XML Configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
 
 <!-- defining CashPayment bean -->
  <bean id="cashPaymentBean" class="org.netjs.exp.Spring_Example.CashPayment" />
 
  <!-- Defining PayServiceImpl bean and injecting payment bean -->
  <bean id="payServiceBean" class="org.netjs.exp.Spring_Example.PayServiceImpl" >
      <property name="payment" ref="cashPaymentBean" />
  </bean>
</beans>

PayServiceImpl class

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

public class PayServiceImpl implements IPayService, InitializingBean, DisposableBean {
 
 private IPayment payment;
 
 public PayServiceImpl(){
  
 }
 public PayServiceImpl(IPayment payment){
  this.payment = payment;
 }
 
 public void performPayment() {
  payment.executePayment();
 }

 public void destroy() throws Exception {
  System.out.println("Calling destroy method");
 }

 public void afterPropertiesSet() throws Exception {
  System.out.println("Calling after properties set method");
 }
 
 public IPayment getPayment() {
  return payment;
 }

 public void setPayment(IPayment payment) {
  this.payment = payment;
 }
}

IPayService interface

public interface IPayService {
 void performPayment();
}

IPayment interface

public interface IPayment {
 void executePayment();
}

CashPayment class

public class CashPayment implements IPayment{
 public void executePayment() {
  System.out.println("Perform Cash Payment "); 
 }
}

Class to run the code

public class App {
  public static void main( String[] args ){
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");
    IPayService bean = (IPayService) context.getBean("payServiceBean");
    bean.performPayment();
    context.close();
  }
}

Output

INFO: Loading XML bean definitions from class path resource [appcontext.xml]
Calling after properties set method
Perform Cash Payment 
Feb 28, 2016 5:54:12 PM org.springframework.context.support.ClassPathXmlApplicationContext doClose
INFO: Closing org.springframework.context.support.ClassPathXmlApplicationContext@1f17ae12: startup date [Sun Feb 28 17:54:11 IST 2016]; root of context hierarchy
Calling destroy method

Custom init/destroy or @PostConstruct/@PreDestroy annotation

As you can see from the above example, using InitializingBean and DisposbleBean interfaces add Spring dependencies to your class so it is recommended to use either custom init and destroy method or @PostConstruct/@PreDestroy annotations. Note that both post-init and pre-destroy methods should have no arguments but they can throw Exceptions.

Infact you can use all 3 of them and in that case order in which these methods will be called is

  • 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

So let's see a Spring bean life cycle example where all three are called, in that case XML Configuration will look like-

 <bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
  <!-- defining CashPayment bean -->
  <bean id="cashPaymentBean" class="org.netjs.exp.Spring_Example.CashPayment" />
 
  <!-- Defining PayServiceImpl bean and injecting payment bean -->
  <bean id="payServiceBean" class="org.netjs.exp.Spring_Example.PayServiceImpl" init-method="customInitMethod" destroy-method="customDestroyMethod">
      <property name="payment" ref="cashPaymentBean" />
  </bean>

Note that bean definition for CommonAnnotationBeanPostProcessor is added, this is required if you are using annotation.

Also with in the PayServiceImpl bean definition, two attributes init-method and destroy-method are added for defining custom init and destroy methods respectively.

And PayServiceImpl class will look like-

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class PayServiceImpl implements IPayService, InitializingBean, DisposableBean {
 
 private IPayment payment;
 
 public PayServiceImpl(){
  
 }
 public PayServiceImpl(IPayment payment){
  this.payment = payment;
 }
 
 public void performPayment() {
  payment.executePayment();
 }
 
 public void destroy() throws Exception {
  System.out.println("Calling destroy method"); 
 }

 public void afterPropertiesSet() throws Exception {
  System.out.println("Calling after properties set method"); 
 }
 
 // for init-method 
 public void customInitMethod(){
  System.out.println("Calling customInitMethod");
 }
 // for destroy-method 
 public void customDestroyMethod(){
  System.out.println("Calling customDestroyMethod");
 }
 
 @PostConstruct
 public void annoInitMethod(){
  System.out.println("Calling annoInitMethod");
 }
 
 @PreDestroy
 public void annoDestroyMethod(){
  System.out.println("Calling annoDestroyMethod");
 }
 public IPayment getPayment() {
  return payment;
 }

 public void setPayment(IPayment payment) {
  this.payment = payment;
 }
}

Output

Calling annoInitMethod
Calling after properties set method
Calling customInitMethod
Perform Cash Payment
Calling annoDestroyMethod
Calling destroy method
Calling customDestroyMethod

Note the order in which init and destroy methods are called.

Spring Aware Interfaces

Sometimes you may need some housekeeping information like the bean name, application context or servlet context, for which you need Spring framework objects. For that purpose Spring provides a number of aware interfaces that you can implement in your bean which will inject the required dependency.

Some of the most used aware interfaces are-

  1. ApplicationContextAware- This interface has setApplicationContext() method which will inject the applicationcontext dependency to the bean. Using it you can programmatically retrieve all the other bean definitions.
  2. BeanNameAware- This interface has setBeanName() method which provides the implementing class with a reference to the name defined in its associated object definition.
  3. BeanFactoryAware- This interface when implemented will inject BeanFactory. Using it you can get the bean definition and its attributes.
  4. ServletConfigAware, ServletContextAware to get ServletConfig and ServletContext valid only in in a web-aware Spring ApplicationContext

Refer ApplicationContextAware And BeanNameAware Interfaces in Spring Framework to know more about ApplicationContextAware and BeanNameAware Interfaces.

Refer BeanFactoryAware Interface in Spring Framework to know more about BeanFactoryAware interface.

Spring Aware Interfaces example

Let's create a bean that will implement some of these interfaces and provide some usage using the injected dependencies.

XML Configuration

Definition for new bean AwareBeanDemo is added

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
<!-- defining CashPayment bean -->
<bean id="cashPaymentBean" class="org.netjs.exp.Spring_Example.CashPayment" />
 
<!-- Defining PayServiceImpl bean and injecting payment bean -->
<bean id="payServiceBean" class="org.netjs.exp.Spring_Example.PayServiceImpl" init-method="customInitMethod"
    destroy-method="customDestroyMethod">
  <property name="payment" ref="cashPaymentBean" />
</bean>

<bean id="awareBeanDemo" class="org.netjs.exp.Spring_Example.AwareBeanDemo" />

AwareBeanDemo class

import java.util.Arrays;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class AwareBeanDemo implements ApplicationContextAware, BeanNameAware, BeanFactoryAware{
 @Override
 public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
  System.out.println("In setBeanFactory");
  // Getting another bean and calling its method
  IPayService payService = (IPayService)beanFactory.getBean("payServiceBean");
  payService.performPayment();
 }
 
 @Override
 public void setBeanName(String name) {
  System.out.println("In setBeanName");
  System.out.println("Bean name - " + name);  
 }
 
 @Override
 public void setApplicationContext(ApplicationContext appCtx)
   throws BeansException {
  System.out.println("In setApplicationContext");
  // Getting all the bean definitions
  String[] beanArr = appCtx.getBeanDefinitionNames();
  System.out.println( ""+ Arrays.toString(beanArr));  
 }
}

Output

Calling annoInitMethod
Calling after properties set method
Calling customInitMethod
In setBeanName
Bean name - awareBeanDemo
In setBeanFactory
Perform Cash Payment 
In setApplicationContext
[org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#0, cashPaymentBean, payServiceBean, awareBeanDemo]
Calling annoDestroyMethod
Calling destroy method
Calling customDestroyMethod

Note that some of the output is coming from the init and destroy methods configured for other beans. Relevant output is highlighted,

That's all for this topic Spring Bean Life Cycle. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Spring Tutorial Page


Related Topics

  1. Bean Scopes in Spring With Examples
  2. How to Inject Prototype Scoped Bean into a Singleton Bean in Spring
  3. BeanPostProcessor in Spring Framework
  4. Lazy Initialization in Spring Using lazy-init And @Lazy Annotation
  5. Creating a Maven project in Eclipse

You may also like-

  1. Dependency Injection in Spring Framework
  2. Spring NamedParameterJdbcTemplate Insert, Update And Delete Example
  3. @FunctionalInterface Annotation in Java
  4. equals() And hashCode() Methods in Java
  5. Initializer block in Java
  6. Java CyclicBarrier With Examples
  7. Race Condition in Java Multi-Threading
  8. Add Double Quotes to a String Java Program