Friday, 4 March 2016

Spring bean life cycle

Lifecycle of a bean in a Spring is quite elaborate and provides many callback methods to customize the nature of the bean.

On the basis of functionality, these callback methods provide, you can categorize them 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.

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

  1. InitializingBean and DisposableBean interfaces which you can implement and provide implementation for afterPropertiesSet() for the former (InitializingBean) and destroy() 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.

    Using @PostConstruct and @PreDestroy annotations. If you don't want to use the JSR-250 annotations consider the use of init-method and destroy-method object definition metadata.

    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.

  3. Other aware interfaces like ApplicationContextAware and BeanNameAware.
bean lifecycle in Spring
Spring bean lifecycle methods

Here note that you have three options for controlling bean lifecycle behavior:

the InitializingBean and DisposableBean callback interfaces; 
custom init() and destroy() methods; and 
the @PostConstruct and @PreDestroy annotations. 

You can combine these mechanisms to control a given bean.

If multiple lifecycle 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 DisposbleBean callback interfaces

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

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

Example code

Let's see an example where we have PayServiceImpl bean which will implement InitializingBean and DisposbleBean 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

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 an 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 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

Example code

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 Life cycle of a bean in Spring. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Different bean scopes in Spring
  2. How to inject prototype scoped bean in singleton bean
  3. What is Dependency Injection in Spring
  4. Constructor-based dependency injection in Spring
  5. Spring example program using JavaConfig and Annotations
  6. Creating a Maven project in Eclipse

You may also like -

>>>Go to Spring tutorial page

1 comment: