In Spring framework it is the Spring container that is responsible for instantiating beans, setting bean properties,
wiring dependencies and managing the complete bean lifecycle from its instantiation to the time bean is destroyed.
Spring bean lifecycle callbacks
To interact with the container’s management of the bean lifecycle, in order to customize the nature of a bean, Spring
Framework provides a number of interfaces which can be categorized into following categories-
- Lifecycle Callbacks
- ApplicationContextAware and BeanNameAware
- Other Aware Interfaces
Spring bean lifecycle callback methods
Spring framework provides callback methods that can be configured to be called-
- After the bean is initialized i.e. post initialization call back methods.
- Before the bean is destroyed i.e. pre destruction call back methods.
In Spring bean lifecycle post initialization call back methods are-
- The InitializingBean callback interface provides a method afterPropertiesSet() that can be used for initialization work.
- Methods annotated with @PostConstruct
- Custom init() method
In Spring bean lifecycle pre destruction call back methods are-
- The DisposableBean callback interface provides a method destroy() which lets a bean get a callback when the container that contains it is destroyed.
- Methods annotated with @PreDestroy
- Custom destroy() method
Spring bean lifecycle callback methods execution order
If multiple lifecycle callbacks are configured for the same bean then different initialization methods are called as
follows-
- Methods annotated with @PostConstruct
- afterPropertiesSet() as defined by the InitializingBean callback interface
- A custom configured init() method
Destroy methods are called in the following order:
- Methods annotated with @PreDestroy
- destroy() as defined by the DisposableBean callback interface
- A custom configured destroy() method
Callbacks for ApplicationContextAware and BeanNameAware interfaces is invoked after setting of bean properties but before
an initialization callback such as InitializingBean or a custom init-method.
Following image shows the call back method flow after the bean is instantiated.
Following image shows the call back method flow before the bean is destroyed.
InitializingBean and DisposableBean callback interfaces
The org.springframework.beans.factory.InitializingBean
interface has a single method afterPropertiesSet()
. By implementing
this method you provide a post initialization call back method that let bean perform initialization work after the container
has set all necessary properties on the bean.
The org.springframework.beans.factory.DisposableBean
interface has a single method destroy()
.
By implementing this method you provide a pre destruction call back method that is called when the container that contains
the bean is destroyed.
As per Spring docs it is not recommended to use the InitializingBean and DisposableBean callback interfaces as it
unnecessarily couples the code to Spring. Using annotations @PostConstruct and @PreDestroy or custom init() and destroy()
methods should be preferred.
InitializingBean and DisposableBean interfaces example
In the example there is a class OrderServiceImpl which has a dependency on Store. OrderServiceImpl class implements
InitializingBean and DisposableBean interfaces and provides the callback methods.
public interface OrderService {
public void buyItems();
}
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
public class OrderServiceImpl implements OrderService, InitializingBean, DisposableBean {
private IStore store;
@Autowired
public OrderServiceImpl(IStore store){
this.store = store;
}
// post initialization callback
public void afterPropertiesSet() throws Exception {
System.out.println("In afterPropertiesSet method for bean initialization work");
}
// pre destruction callback
public void destroy() throws Exception {
System.out.println("In destroy() method, cleaning up resources");
}
public void buyItems() {
store.doPurchase();
}
}
public interface IStore {
public void doPurchase();
}
public class RetailStore implements IStore {
public void doPurchase() {
System.out.println("Doing purchase from Retail Store");
}
}
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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config />
<!-- Store bean -->
<bean id="store" class="com.knpcode.springproject.service.RetailStore" />
<!-- OrderServiceImpl bean with store bean dependency -->
<bean id="orderBean" class="com.knpcode.springproject.service.OrderServiceImpl" />
</beans>
You can use the following class with main method to read the configuration and call the bean method.
public class App {
public static void main( String[] args ){
// create context using configuration
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");
OrderService order = context.getBean("orderBean", OrderServiceImpl.class);
order.buyItems();
context.close();
}
}
Output
10:58:24.120 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
10:58:24.128 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
10:58:24.156 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'store'
10:58:24.187 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'orderBean'
10:58:24.287 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'orderBean' via constructor to bean named 'store'
In afterPropertiesSet method for bean initialization work
Doing purchase from Retail Store
In destroy() method, cleaning up resources
As you can see from the output first beans are instantiated and dependencies are wired after that afterPropertiesSet()
callback method is called. When the container is closed at that time destroy() method is called on the bean.
Custom init and destroy methods in Spring bean lifecycle
You can also configure custom init and destroy callback methods using init-method and destroy-method attributes of the
element. For example
<bean id="orderBean" class="com.knpcode.springproject.service.OrderServiceImpl"
init-method="initMethod" destroy-method="destroyMethod" />
Default init and destroy methods
You can also configure custom init and destroy callback methods globally to be called for all the beans defined with in
element. That way you don't need to configure init and destroy attributes with each bean definition. At the same time
you do need to have same method name for post initialization and pre destruction in each bean class. For example-
<beans default-init-method="init" default-destroy-method="destroy">
<bean id="orderBean" class="com.knpcode.springproject.service.OrderServiceImpl"
<property name="store" ref="storeBean" />
</bean>
<bean>.....</bean>
....
....
</beans>
@PostConstruct and @PreDestroy annotations in Spring bean lifecycle
A method annotated with @PostConstruct is considered a post initialization method where as a method annotated with
@PreDestroy is considered a predestruction method.
Spring bean lifecycle callback methods example
In this example we’ll see use of all the three initialization and disposable methods that way you can check the order in
which these methods are called.
Note that for using @PostConstruct and @PreDestroy annotations javax annotation API is needed. We need to add dependency
for this explicitly Java 9 onward.
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
Here is a class which has all the types of initialization and disposable methods.
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class OrderServiceImpl implements OrderService, InitializingBean, DisposableBean {
private IStore store;
@Autowired
public OrderServiceImpl(IStore store){
this.store = store;
}
// post initialization callback
public void afterPropertiesSet() throws Exception {
System.out.println("In afterPropertiesSet method for bean initialization work");
}
// pre destruction callback
public void destroy() throws Exception {
System.out.println("In destroy() method, cleaning up resources");
}
public void initMethod() {
System.out.println("call init method");
}
public void destroyMethod() {
System.out.println("call destroy method");
}
@PostConstruct
public void initAnnotationMethod() {
System.out.println("call init method for post construct");
}
@PreDestroy
public void destroyAnnotationMethod() {
System.out.println("call destroy method for pre destroy");
}
public void buyItems() {
store.doPurchase();
}
}
Output
call init method for post construct
In afterPropertiesSet method for bean initialization work
call init method
Doing purchase from Retail Store
call destroy method for pre destroy
In destroy() method, cleaning up resources
call destroy method
As you can see first the methods annotated with @PostConstruct and @PreDestroy annotations are called. After that
afterPropertiesSet() and destroy() methods are called and at the last custom configured init() and destroy() methods
are called.
Aware interfaces in Spring framework
In Spring framework there are many Aware callback interfaces that let beans indicate to the container that they require
a certain infrastructure dependency.
Some of the most important Aware interfaces are-
- ApplicationContextAware- This interface has setApplicationContext() method which injects the ApplicationContext dependency into the bean. Using this ApplicationContext reference beans can programmatically manipulate the ApplicationContext that created them.
- BeanNameAware- This interface has setBeanName() method. Class that implements the org.springframework.beans.factory.BeanNameAware interface is provided with a reference to the name defined in its associated object definition.
- BeanFactoryAware- By implementing this interface bean will be injected with the declared BeanFactory. Using it you can get the bean definition and its attributes.
- ServletConfigAware- This interface is valid only in in a web-aware Spring ApplicationContext and injects the Current ServletConfig the container runs in.
- ServletContextAware- This interface is valid only in in a web-aware Spring ApplicationContext and injects the Current ServletContext the container runs in.
Spring Aware interfaces example
In the following example bean class implements ApplicationContextAware, BeanNameAware and BeanFactoryAware interfaces.
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 ExampleBean implements ApplicationContextAware, BeanNameAware, BeanFactoryAware{
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("In setBeanFactory method");
// Getting another bean and calling its method
OrderService orderService = (OrderService)beanFactory.getBean("orderBean");
orderService.buyItems();
}
public void setBeanName(String name) {
System.out.println("In setBeanName method");
System.out.println("Bean's name- " + name);
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("In setApplicationContext");
OrderService orderService = (OrderService)applicationContext.getBean("orderBean");
orderService.buyItems();
}
}
Output
In setBeanName method
Bean's name- exampleBean
In setBeanFactory method
14:33:52.227 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'orderBean'
14:33:52.300 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'orderBean' via constructor to bean named 'store'
call init method for post construct
In afterPropertiesSet method for bean initialization work
call init method
Doing purchase from Retail Store
In setApplicationContext
Doing purchase from Retail Store
Doing purchase from Retail Store
call destroy method for pre destroy
In destroy() method, cleaning up resources
call destroy method
That's all for the topic Spring Bean Lifecycle Callback Methods. If something is missing or you have
something to share about the topic please write a comment.
You may also like