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-
- Callback methods called at the time of instantiating a bean.
- Callback methods called at the time of disposing a bean.
- Spring bean life cycle callback methods
- Spring bean life cycle methods execution order
- InitializingBean and DisposableBean callback interfaces
- Spring bean life cycle example - InitializingBean and DisposableBean
- Custom init/destroy or @PostConstruct/@PreDestroy annotation
- Spring Aware Interfaces
- Spring Aware Interfaces example
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.
- InitializingBean and DisposableBean interfaces which you can implement and provide implementation of
afterPropertiesSet()
method for the former (InitializingBean) anddestroy()
method for the latter (DisposableBean) to allow the bean to perform certain actions upon initialization and destruction of your beans. 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.If you don't want to use the JSR-250 annotations you can use
init-method
anddestroy-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.
- Other aware interfaces like ApplicationContextAware And BeanNameAware.
You can also combine these options to control a given bean.
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-
- 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. - BeanNameAware- This interface has
setBeanName()
method which provides the implementing class with a reference to the name defined in its associated object definition. - BeanFactoryAware- This interface when implemented will inject BeanFactory. Using it you can get the bean definition and its attributes.
- 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
You may also like-