Spring Bean Life Cycle Example – @PostConstruct, @PreDestroy, InitializingBean, DisposableBean, init-method and destroy-method
In this tutorial we will discuss the Spring Bean Life Cycle, doing so will give you a better understanding of the BeanFactory, which is responsible for managing the lifecycle of beans in the IoC container, and will allow you to perform actions during the creation and destruction of the bean itself. These activities or events are referred to as Bean Life Cycle events.
As of Spring 2.5 and greater, there are 3 ways to control life cycle events of a bean:
- Using InitializingBean and DisposableBean callback interfaces
- Using @PostConstruct and @PreDestroy Java annotations
- Using init-method, destroy-method attribute in bean element in spring config file
We will also briefly touch upon Spring Aware interfaces.
- Using Spring Aware interfaces for certain behaviors
Lets discuss each of these in detail.
InitializingBean and DisposableBean callback interfaces
Spring allows us to hook into the management of the bean lifecycle in the IoC container, by implementing the org.springframework.beans.factory.InitializingBean and org.springframework.beans.factory.DisposableBean interfaces. Each of the interfaces declare a single method, one is used during the initialization and setup of the bean and one is used during the destruction of the bean.
The InitializingBean interface specifies one method afterPropertiesSet() which throws Exception.
@Override public void afterPropertiesSet() throws Exception { // .... }
The DisposableBean interface is used to release resources or perform some cleanup actions prior destruction of the bean by the IoC container. The DisposableBean interface specifies one method destroy() which throws Exception.
@Override public void destroy() throws Exception { // .... }
MyUserAccount implementing InitializingBean, DisposableBean Interfaces
Below you will find a sample implementation and what it would look like.
package com.avaldes.tutorial; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; public class MyUserAccount implements InitializingBean, DisposableBean { private User user; private String accountNo; private int accountType; private boolean active; @Override public void destroy() throws Exception { System.out.println("Inside MyUserAccount destroy() method..."); } @Override public void afterPropertiesSet() throws Exception { System.out.println("Inside MyUserAccount afterPropertiesSet() method..."); } public User getUser() { return user; } public void setUser(User user) { this.user = user; } public String getAccountNo() { return accountNo; } public void setAccountNo(String accountNo) { this.accountNo = accountNo; } public int getAccountType() { return accountType; } public void setAccountType(int accountType) { this.accountType = accountType; } public boolean isActive() { return active; } public void setActive(boolean active) { this.active = active; } @Override public String toString() { return "MyUserAccount [user=" + user + ", accountNo=" + accountNo + ", accountType=" + accountType + ", active=" + active + "]"; } }
Note
Use of InitializingBean and DisposableBean is not recommended as using these interfaces causes a tight coupling to the Spring Framework. The recommended approach is to use @PostConstruct and @PreDestroy annotations in your Java code or use the init-method and destroy-method attribute in the bean element in the spring configuration files for bean lifecycle management.
@PostConstruct and @PreDestroy Java Annotations
This is the recommended way of hooking into the stages of the bean lifecycle. Specifically during the post-creation phase and pre-destruction phases of the bean. Please note that @PostConstruct and @PreDestroy annotations are a Java standard way which uses the javax.annotation package. This prevents the tight coupling seen when using the InitializingBean and DisposableBean interfaces.
Lets look at some java code snippets for these annotations.
The @PostConstruct annotation will be called right after the bean has been instantiated and before its instance has been returned to the caller.
@PostConstruct public void init() { System.out.println("Inside UserAccount init() method..."); }
The @PreDestroy annotation just before the bean is to be destroyed by the container to allow for any actions or cleanup to take place.
@PreDestroy public void destroy() { System.out.println("Inside UserAccount destroy() method..."); }
UserAccount using @PostConstruct and @PreDestroy Annotations for Bean Lifecycle
Below you will find a sample implementation and what it would look like.
package com.avaldes.tutorial; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; public class UserAccount { private User user; private String accountNo; private int accountType; private boolean active; @PostConstruct public void init() { System.out.println("Inside UserAccount init() method..."); } @PreDestroy public void destroy() { System.out.println("Inside UserAccount destroy() method..."); } public User getUser() { return user; } public void setUser(User user) { this.user = user; } public String getAccountNo() { return accountNo; } public void setAccountNo(String accountNo) { this.accountNo = accountNo; } public int getAccountType() { return accountType; } public void setAccountType(int accountType) { this.accountType = accountType; } public boolean isActive() { return active; } public void setActive(boolean active) { this.active = active; } @Override public String toString() { return "UserAccount [user=" + user + ", accountNo=" + accountNo + ", accountType=" + accountType + ", active=" + active + "]"; } }
@Bean Java Annotation
Beans that have been declared in a @Configuration-annotated class support bean lifecycle callbacks. The @Bean annotation replicates the same functionality as the <bean id=”…” class=”…”> specification in the Spring configuration XML file and it supports some of the attributes like init-method, destroy-method, name, and auto-wiring. Ijn addition, it support allows you to specify the init and destroy methods via the following annotation.
public class myClass { public void init() { // perform post-creation logic here } public void destroy() { // perform pre-destruction cleanup of resources here } } @Configuration public class AppConfig { @Bean(initMethod = "init", destroyMethod = "destroy" ) public myClass myclass() { return new myClass (); } }
Using Custom init-method and destroy-method Attributes in Bean Configuration File
The second way of hooking into the stages of the bean lifecycle without coupling your classes to Spring interfaces is through the use of init-method and destroy-method attributes in the Spring Bean Configuration XML file. If you prefer this mechanism and you would like to set this up for multiple beans in your configuration file it quickly becomes a burdensome process to have to do it for every bean. Spring allows us to specify defaults for the init and destroy methods that will work across all beans provided that the beans have the named methods with the proper signature.
Spring Configuration XML
<bean id="userAccount2" class="com.avaldes.tutorial.UserAccountSP" init-method="myInit" destroy-method="myDestroy"> <property name="user" ref="user2" /> <property name="accountNo" value="435-78429085" /> <property name="accountType" value="02" /> </bean>
Custom Initialization and Destroy Methods
package com.avaldes.tutorial; public class UserAccountSP { private User user; private String accountNo; private int accountType; private boolean active; public void myInit() { System.out.println("Inside UserAccountSP init() method..."); } public void myDestroy() { System.out.println("Inside UserAccountSP destroy() method..."); } public User getUser() { return user; } public void setUser(User user) { this.user = user; } public String getAccountNo() { return accountNo; } public void setAccountNo(String accountNo) { this.accountNo = accountNo; } public int getAccountType() { return accountType; } public void setAccountType(int accountType) { this.accountType = accountType; } public boolean isActive() { return active; } public void setActive(boolean active) { this.active = active; } @Override public String toString() { return "UserAccountSP [user=" + user + ", accountNo=" + accountNo + ", accountType=" + accountType + ", active=" + active + "]"; } }
Specifying Default Initialization and Destroy Methods in Bean Configuration File
Spring Framework provides a capability to configure default initialization and default destruction methods using default-init-method and default-destroy-method attributes on the <beans> element as follows:
<?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:beans="http://www.springframework.org/schema/beans" 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" default-init-method="init" default-destroy-method="destroy" > <context:component-scan base-package="com.avaldes.tutorial" /> <bean id="user1" class="com.avaldes.tutorial.User"> <property name="uid" value="123" /> <property name="username" value="amaury.valdes" /> </bean> </beans>
Spring Aware Interfaces
Sometimes we will need to have our beans hook into lower level services that are not provided by Spring framework. In order to do this, Spring offers several Aware interfaces that allow beans to indicate to the container that they require a certain infrastructure dependency.
package com.avaldes.tutorial; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanClassLoaderAware; 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; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.context.MessageSource; import org.springframework.context.MessageSourceAware; import org.springframework.context.ResourceLoaderAware; import org.springframework.context.weaving.LoadTimeWeaverAware; import org.springframework.core.io.ResourceLoader; import org.springframework.instrument.classloading.LoadTimeWeaver; import org.springframework.jmx.export.notification.NotificationPublisher; import org.springframework.jmx.export.notification.NotificationPublisherAware; public class SpringAwareBean implements ApplicationContextAware, ApplicationEventPublisherAware, BeanClassLoaderAware, BeanFactoryAware, BeanNameAware, LoadTimeWeaverAware, MessageSourceAware, NotificationPublisherAware, ResourceLoaderAware { @Override public void setApplicationContext(ApplicationContext arg0) throws BeansException { // TODO Auto-generated method stub } @Override public void setApplicationEventPublisher(ApplicationEventPublisher arg0) { // TODO Auto-generated method stub } @Override public void setLoadTimeWeaver(LoadTimeWeaver arg0) { // TODO Auto-generated method stub } @Override public void setBeanName(String arg0) { // TODO Auto-generated method stub } @Override public void setBeanFactory(BeanFactory arg0) throws BeansException { // TODO Auto-generated method stub } @Override public void setBeanClassLoader(ClassLoader arg0) { // TODO Auto-generated method stub } @Override public void setResourceLoader(ResourceLoader arg0) { // TODO Auto-generated method stub } @Override public void setMessageSource(MessageSource arg0) { // TODO Auto-generated method stub } @Override public void setNotificationPublisher(NotificationPublisher arg0) { // TODO Auto-generated method stub } }
Download the Code
That’s It
Hopefully, you will find this helpful to you in understanding how to hook into the different phases of the bean lifecycle. If you have any questions or comments please let me know.
Please Share Us on Social Media






Leave a Reply