Categories
Spring Spring Core

Spring Bean Life Cycle Callback Methods

As per our Bean Definition in the form of “XML, Java Code or Annotation” the IoC Container will Create, Assemble and Instantiate the Bean Objects for you and it destroys when the Container is Shutdown in case of Singleton and it destroys when Object is no longer needed in case of Prototype Scope. 

If you want to interact with IoC Container to manage your Bean while Instantiation and Destruction of Bean Object, you can use Lifecycle Callback methods.

We will look at those Spring Bean Life Cycle Callback Methods in detail with an Example in this Article.

Available Life-Cycle Callback methods in Spring

  • InitializingBean and DisposableBean interfaces
  • Init-method and destroy-method attribute in XML Configuration
  • @PostConstruct and @PreDestroy annotations

@PostConstruct and @PreDestroy Annotation approach is recommended. However, we can use any of the above three methods or all three methods for callbacks in our application.

If you used all three approaches with different callback methods in your Bean, then Spring will invoke in the below order while Instantiation.

  1. Bean with @PostConstruct defined
  2. InitializingBean Overridden methods
  3. Init-method attribute from XML

The same Annotation then Interface then XML order will be maintained during Bean Destroy as like below.

  1. Bean with @PreDestroy
  2. DisposableBean overridden methods
  3. Destroy-method attribute from XML

InitializingBean and DisposableBean Interfaces

This is not recommended as it is directly coupled with ApplicationContext methods by your Bean. You have to override 

void afterPropertiesSet() throws Exception; 

and

void destroy() throws Exception; in your Bean Directly. 

Instead of Using the Interface approach you can use XML Attributes to achieve life cycle callbacks.

“init-method” and “destroy-method” XML Attribute with Example

It is recommended if you are not using a modern Annotation approach in your application. 

We shall learn with a simple example for better understanding.

Create a Maven Project and name it as SpringLifeCycleCallbacks and add below dependencies in the pom.xml file.

<dependencies>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>5.2.5.RELEASE</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>5.2.5.RELEASE</version>
		</dependency>
	</dependencies>

EmployeeController : Create a controller class and add init and destroy methods with void return type.

public class EmployeeController {
	public void init() {
		System.out.println("Init method Invoked");
	}
	
	public EmployeeController(){
		System.out.println("EmployeeController Initialized");
	}
	
	public void addNewEmployee() {
		System.out.println("Adding new employee business logic goes here");
	}
	
	public void destroy() {
		System.out.println("Destroy Method Invoked");
	}
}

Configuration Meta-Data

Create applicationContext.xml file in the src folder and copy the below code.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
        
        <bean id="employeeController" class="EmployeeController" init-method="init" destroy-method="destroy"></bean>
        
</beans>

In the above coding snippet i have added a Bean definition of employeeController Class which we created already with life cycle methods mentioned in init-method and destroy-method attributes. 

The values “init” and “destroy” indicate the method name in EmployeeController class.

You can provide any name instead of init and destroy as method name. Using generic and easily understandable method names is preferred to understand the code by other developers. 

Starter Class : Create EmployeeStarter class and configure ApplicationContext IoC Container to make our application configured and running.

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class EmployeeStarter {

	public static void main(String[] args) {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
		EmployeeController controller = applicationContext.getBean("employeeController",EmployeeController.class);
		controller.addNewEmployee();
	}

}

The final folder structure of your application will be like below.

Now run the above application from EmployeeStarter class, you are able to see the logs return in console.

  • As per the above logs. The IoC Container first Create a Bean and initialized it and then called the Lifecycle Methods
  • Init Method is called here after the Bean is initialized
  • Destroy method will call when the Context is destroyed

@PostConstruct and @PreDestroy annotations with Example

Using Annotation is a recommended approach for Spring Bean Life-Cycle callbacks. 

All you need to slightly modify the above example code as I mentioned below.

Controller Class : Modify Controller class with @PostConstruct and @PreDestroy annotations.

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class EmployeeController {
	@PostConstruct
	public void init() {
		System.out.println("Init method Invoked");
	}
	
	public EmployeeController(){
		System.out.println("EmployeeController Initialized");
	}
	
	public void addNewEmployee() {
		System.out.println("Adding new employee business logic goes here");
	}
	
	@PreDestroy
	public void destroy() {
		System.out.println("Destroy Method Invoked");
	}
}

In the above example code i added @PostConstruct on top of init() method. And @PreDestroy annotation on top of destroy() method to receive callbacks.

applicationContext.xml : Modify Configuration Meta-Data to communicate IoC Container to make use of Annotations in our application classes.

<context:annotation-config></context:annotation-config>

Without this code in XML Configuration, IoC Container won’t recognize you are using annotations in your Bean Classes.

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

	<context:annotation-config></context:annotation-config>
	<bean id="employeeController" class="EmployeeController"></bean>

</beans>

The whole Meta-Data will look like above. 

Now run the program with these small changes, you can expect the same output as came from the init-method and destroy-method attribute approach.

Flow of Life-Cycle Callback Methods

  1. IoC Container configured and initialized
  2. Started creating and configuring Bean Objects.
  3. Before Configuring requested Bean’s, Container will create and configure its Dependencies
  4. Inject the Dependencies while creating and Initializing the actual Bean.
  5. After the Bean is Initialized callback method will invoke.
  6. Method name mentioned in init-method attribute or annotated with @PostConstruct method is invoked.
  7. All other business logic will happen after the init method. In our case addNewEmployee is Called.
  8. Upon request to shut-down the system or server, the Container will get Destroyed.
  9. Before destroying the container destroy() method will be invoked.
  10. IoC Container destroyed.

Key Terms :

  • The first preferred way for Bean Life-Cycle callbacks is using @PostConstruct and @PreDestroy annotations. If your application is not using annotation based configuration, then you can go with XML Based init-method and destroy-method attributes.
  • Init-method and destroy-method attribute example code
    • <bean id=”employeeController” class=”EmployeeController” init-method=”init” destroy-method=”destroy”></bean>
    • You can use any name instead of “init” and “destroy” for callback methods.
    • Using a common name throughout the application is preferred. 
  • Instead of providing callback methods for every bean definition, you can mention it as default-init-method in Beans tag. This will invoke the init method in every bean object configured in the container.
    • Example Code : <beans default-init-method=”init” default-destroy-method=”destroy”>
    • This is equivalent to defining init-method and destroy-method in every bean definition.
  • If you combine all three approaches on Spring Bean Life-Cycle callbacks, Container will invoke @PostConstruct annotated method first and then it will invoke the init-method attribute mentioned in XML Configuration file.
  • You can manually Shut-down the IoC Container using ConfigurableApplicationContext interface as like below by modifying EmployeeStarter class.
    • ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext(“applicationContext.xml”);

Benefits of Using Lifecycle Callbacks

  • Instead of the finalize() method from Core-Java you can use @PreDestroy.
  • Before using the defined methods of Bean, you can check whether it is initialized or not in init() method using @PostConstruct. This will reduce application exceptions and many more advantages are there based on the application use case.

That’s all for now on the LifeCycle Callback Method in Spring Framework.

Happy Reading!!!

Leave a Reply

Your email address will not be published. Required fields are marked *