Spring container manages the life cycle of spring bean like
- Creation of bean
- Dependency injection
- Setting properties
- Destruction of bean
So as a developer, we don’t have to worry about the above points because the container manages all the above steps and we don’t have to write any boilerplate code.
But as a developer how we can be part of the life cycle of spring beans?
- We can do all the prerequisites and prior validations for the bean once the bean initialization completes.
- We can do all the cleanup steps for the bean before the container destroys the bean.
Table of contents
Ways to implement the life cycle of the bean
There are 4 ways to implement the life cycle of the bean
- Using XML Configuration
- Using Programmatic approach ( Using Interfaces )
- Using Annotations
- Aware Interfaces
XML Configuration
As we know in the configuration file we will be defining the spring beans. Spring container will read this configuration file.
While defining the bean we can make use of the init-method attribute to define the initialization method that will perform the pre-requisites and validations for that bean. The container will call the init method after setting the properties of the bean. We can also make use of the destroy-method attribute to define the destroy method where we can write all the clean-up steps. The container will call the destroy method just before destroying the bean.
Below is the configuration file to define the bean and its properties
<?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"> <!-- Define your beans here --> <bean id="manager" class="com.getinputs.Manager" init-method="init" destroy-method="destroy"> <property name="name" value="Suraj"></property> <property name="salary" value="50000"></property> </bean> </beans>
init and destroy methods are the life cycle method of spring beans. Below we are creating a bean that will have init and destroy methods.
package com.getinputs; public class Manager { String name; int salary; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } public void init() { System.out.println("init method is called after properties are set"); System.out.println("Name of manager is : " + getName()); System.out.println("Salary of manager is : " + getSalary()); } public void destroy() { System.out.println("destroy method is called just before bean gets destroyed"); } }
Now we will create the application context and call the methods of the spring bean so as to check when the container will call the life cycle methods of the spring bean.
package com.getinputs; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringDemoApp { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Manager manager = context.getBean("manager", Manager.class); manager.getName(); manager.getSalary(); context.close(); System.out.println("Context is closed hence bean is destroyed"); } } Output: init method is called after properties are set Name of manager is: Suraj Salary of manager is: 50000 destroy method is called just before bean gets destroyed Context is closed hence bean is destroyed
Repository link
https://github.com/getinputs/samples/tree/main/lifecyclebean_xml
Programmatic approach
Spring bean can implement the InitializingBean interface and DisposableBean interface.
InitializingBean interface
A bean can implement this interface if they need to react once all the properties are set by the container. The InitializingBean interface is having an afterPropertiesSet() method to perform validations or some custom initialization to check if all the mandatory properties are been set for the bean.
The InitializingBean interface is equivalent to the init method from the XML configuration example.
DisposableBean interface
A bean can implement this interface if that bean wants to release resources before destruction. A BeanFactory will invoke the destroy method on individual destruction of a scoped bean. DisposableBean interface is having a destroy method to clean up all the resources which the container calls before it destroys the bean.
The DisposableBean interface is equivalent to destroy method from the XML configuration example.
Example using interface
Below is the configuration file to define the bean and its properties
<?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"> <!-- Define your beans here --> <bean id="manager" class="com.getinputs.Manager"> <property name="name" value="Suraj"></property> <property name="salary" value="50000"></property> </bean> </beans>
Below is the spring bean which implements InitializingBean and DisposableBean interface to implement the afterPropertiesSet method and destroy method.
package com.getinputs; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; public class Manager implements InitializingBean, DisposableBean { String name; int salary; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } @Override public void afterPropertiesSet() throws Exception { System.out.println("init method is called after properties are set"); System.out.println("Name of manager is : " + getName()); System.out.println("Salary of manager is : " + getSalary()); } @Override public void destroy() throws Exception { System.out.println("destroy method is called just before bean gets destroyed"); } }
Now we will create the application context and call the methods of the spring bean so as to check when the container will call the life cycle methods of the spring bean.
package com.getinputs; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringDemoApp { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Manager manager = context.getBean("manager", Manager.class); manager.getName(); manager.getSalary(); context.close(); System.out.println("Context is closed hence bean is destroyed"); } } Output: init method is called after properties are set Name of manager is: Suraj Salary of manager is: 50000 destroy method is called just before bean gets destroyed Context is closed hence bean is destroyed
Repository link
https://github.com/getinputs/samples/tree/main/lifecyclebean_interface
Annotations
Spring has provided 2 annotations @PostConstruct and @PreDestroy annotations
PostConstruct
The container will call the @PostConstruct method once all the properties are set.
It behaves as an init method from XML configuration and an afterPropertiesSet method from the programmatic approach. It helps us to perform prerequisites and validations on the bean.
PreDestroy
The container will call the @PreDestroy method just before it destroys the bean.
It behaves as destroy method from XML configuration and destroy method from the programmatic approach. It helps us to perform some clean-up activities.
We have to configure our spring application such that it should understand these annotations. We can do this by using the below element in the spring bean configuration file.
context:annotation-config
Below is the configuration file to define the bean and its properties
<?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"> <!-- Define your beans here --> <bean id="manager" class="com.getinputs.Manager"> <property name="name" value="Suraj"></property> <property name="salary" value="50000"></property> </bean> <!-- only looks for annotations on beans in the same application context it is defined in --> <context:annotation-config/> </beans>
Below is the spring bean which will have @PostConstruct and @PreDestroy annotated methods.
package com.getinputs; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; public class Manager { String name; int salary; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } @PostConstruct public void init() { System.out.println("init method is called after properties are set"); System.out.println("Name of manager is : " + getName()); System.out.println("Salary of manager is : " + getSalary()); } @PreDestroy public void destory() { System.out.println("destroy method is called just before bean gets destroyed"); } }
Now we will create the application context and call the methods of the spring bean so as to check when the container will call the life cycle methods of the spring bean.
package com.getinputs; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringDemoApp { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Manager manager = context.getBean("manager", Manager.class); manager.getName(); manager.getSalary(); context.close(); System.out.println("Context is closed hence bean is destroyed"); } } Output: init method is called after properties are set Name of manager is: Suraj Salary of manager is: 50000 destroy method is called just before bean gets destroyed Context is closed hence bean is destroyed
Repository link
https://github.com/getinputs/samples/tree/main/lifecyclebean_annotation
Aware Interfaces
We are having few Aware interfaces which also constitute the life cycle of a bean but they are rarely used. One of them is BeanNameAware Interface.
BeanNameAware Interface
The bean that is implementing this interface can get its name defined in the Spring container.
Below is the configuration file to define the bean and its properties
<?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"> <!-- Define your beans here --> <bean id="manager" class="com.getinputs.Manager" init-method="init" destroy-method="destroy"> <property name="name" value="Suraj"></property> <property name="salary" value="50000"></property> </bean> </beans>
Below is the bean which implements BeanNameAware Interface.
package com.getinputs; import org.springframework.beans.factory.BeanNameAware; public class Manager implements BeanNameAware { String name; int salary; @Override public void setBeanName(String beanName) { System.out.println("Bean name is : " + beanName); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } public void init() { System.out.println("init method is called after properties are set"); System.out.println("Name of manager is : " + getName()); System.out.println("Salary of manager is : " + getSalary()); } public void destroy() { System.out.println("destroy method is called just before bean gets destroyed"); } }
Now we will create the application context and call the methods of the spring bean so as to check when the container will call the life cycle methods of the spring bean.
Note* Here bean name is the id attribute value which we defined in the configuration file.
package com.getinputs; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringDemoApp { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Manager manager = context.getBean("manager", Manager.class); manager.getName(); manager.getSalary(); context.close(); System.out.println("Context is closed hence bean is destroyed"); } } Output: Bean name is : manager init method is called after properties are set Name of manager is : Suraj Salary of manager is : 50000 destroy method is called just before bean gets destroyed Context is closed hence bean is destroyed
Repository link
https://github.com/getinputs/samples/tree/main/lifecyclebean_beannameaware
We are also having a few more aware interfaces like ApplicationContextAware, BeanFactoryAware, MessageSourceAware, ServletContextAware, ServletConfigAware, ApplicationEventPublisherAware, and ResourceLoaderAware which can also be used in the life cycle of the spring bean. Here are a few links that can help you to get more understanding of these interfaces
http://javainsimpleway.com/spring-aware-interfaces-for-beans/
http://www.javabyexamples.com/quick-guide-to-spring-aware-interfaces
So this is all about the life cycle of spring beans. I hope you found this article interesting and valuable. If you are having any concerns or questions about this article please comment below and please share it to help me grow.