The life cycle of spring beans

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.


Ways to implement the life cycle of the bean

There are 4 ways to implement the life cycle of the bean

  1. Using XML Configuration
  2. Using Programmatic approach ( Using Interfaces )
  3. Using Annotations
  4. 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

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

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

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

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.

Leave a Comment