Spring Bean Life Cycle

Filed Under: Spring

Today we will look into Spring Bean Life Cycle. Spring Beans are the most important part of any Spring application. Spring ApplicationContext is responsible to initialize the Spring Beans defined in spring bean configuration file.

Spring Bean Life Cycle

spring bean life cycle
Spring Context is also responsible for injection dependencies in the bean, either through setter or constructor methods or by spring autowiring.

Sometimes we want to initialize resources in the bean classes, for example creating database connections or validating third party services at the time of initialization before any client request. Spring framework provide different ways through which we can provide post-initialization and pre-destroy methods in a spring bean life cycle.

  1. By implementing InitializingBean and DisposableBean interfaces – Both these interfaces declare a single method where we can initialize/close resources in the bean. For post-initialization, we can implement InitializingBean interface and provide implementation of afterPropertiesSet() method. For pre-destroy, we can implement DisposableBean interface and provide implementation of destroy() method. These methods are the callback methods and similar to servlet listener implementations.

    This approach is simple to use but it’s not recommended because it will create tight coupling with the Spring framework in our bean implementations.

  2. Providing init-method and destroy-method attribute values for the bean in the spring bean configuration file. This is the recommended approach because of no direct dependency to spring framework and we can create our own methods.

Note that both post-init and pre-destroy methods should have no arguments but they can throw Exceptions. We would also require to get the bean instance from the spring application context for these methods invocation.

Spring Bean Life Cycle – @PostConstruct, @PreDestroy Annotations

Spring framework also support @PostConstruct and @PreDestroy annotations for defining post-init and pre-destroy methods. These annotations are part of javax.annotation package. However for these annotations to work, we need to configure our spring application to look for annotations. We can do this either by defining bean of type org.springframework.context.annotation.CommonAnnotationBeanPostProcessor or by context:annotation-config element in spring bean configuration file.

Let’s write a simple Spring application to showcase the use of above configurations for spring bean life cycle management. Create a Spring Maven project in Spring Tool Suite, final project will look like below image.

spring bean life cycle example methods

Spring Bean Life Cycle – Maven Dependencies

We don’t need to include any extra dependencies for configuring spring bean life cycle methods, our pom.xml file is like any other standard spring maven project.


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.springframework.samples</groupId>
  <artifactId>SpringBeanLifeCycle</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <properties>

		<!-- Generic properties -->
		<java.version>1.7</java.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

		<!-- Spring -->
		<spring-framework.version>4.0.2.RELEASE</spring-framework.version>

		<!-- Logging -->
		<logback.version>1.0.13</logback.version>
		<slf4j.version>1.7.5</slf4j.version>

	</properties>
	
	<dependencies>
		<!-- Spring and Transactions -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>

		<!-- Logging with SLF4J & LogBack -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${slf4j.version}</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>${logback.version}</version>
			<scope>runtime</scope>
		</dependency>

	</dependencies>	
</project>

Spring Bean Life Cycle – Model Class

Let’s create a simple java bean class that will be used in service classes.


package com.journaldev.spring.bean;

public class Employee {

	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
}

Spring Bean Life Cycle – InitializingBean, DisposableBean

Let’s create a service class where we will implement both the interfaces for post-init and pre-destroy methods.


package com.journaldev.spring.service;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

import com.journaldev.spring.bean.Employee;

public class EmployeeService implements InitializingBean, DisposableBean{

	private Employee employee;

	public Employee getEmployee() {
		return employee;
	}

	public void setEmployee(Employee employee) {
		this.employee = employee;
	}
	
	public EmployeeService(){
		System.out.println("EmployeeService no-args constructor called");
	}

	@Override
	public void destroy() throws Exception {
		System.out.println("EmployeeService Closing resources");
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("EmployeeService initializing to dummy value");
		if(employee.getName() == null){
			employee.setName("Pankaj");
		}
	}
}

Spring Bean Life Cycle – Custom post-init, pre-destroy

Since we don’t want our services to have direct spring framework dependency, let’s create another form of Employee Service class where we will have post-init and pre-destroy spring life cycle methods and we will configure them in the spring bean configuration file.


package com.journaldev.spring.service;

import com.journaldev.spring.bean.Employee;

public class MyEmployeeService{

	private Employee employee;

	public Employee getEmployee() {
		return employee;
	}

	public void setEmployee(Employee employee) {
		this.employee = employee;
	}
	
	public MyEmployeeService(){
		System.out.println("MyEmployeeService no-args constructor called");
	}

	//pre-destroy method
	public void destroy() throws Exception {
		System.out.println("MyEmployeeService Closing resources");
	}

	//post-init method
	public void init() throws Exception {
		System.out.println("MyEmployeeService initializing to dummy value");
		if(employee.getName() == null){
			employee.setName("Pankaj");
		}
	}
}

We will look into the spring bean configuration file in a bit. Before that let’s create another service class that will use @PostConstruct and @PreDestroy annotations.

Spring Bean Life Cycle – @PostConstruct, @PreDestroy

Below is a simple class that will be configured as spring bean and for post-init and pre-destroy methods, we are using @PostConstruct and @PreDestroy annotations.


package com.journaldev.spring.service;

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

public class MyService {

	@PostConstruct
	public void init(){
		System.out.println("MyService init method called");
	}
	
	public MyService(){
		System.out.println("MyService no-args constructor called");
	}
	
	@PreDestroy
	public void destory(){
		System.out.println("MyService destroy method called");
	}
}

Spring Bean Life Cycle – Configuration File

Let’s see how we will configure our beans in spring context file.


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

<!-- Not initializing employee name variable-->
<bean name="employee" class="com.journaldev.spring.bean.Employee" />

<bean name="employeeService" class="com.journaldev.spring.service.EmployeeService">
	<property name="employee" ref="employee"></property>
</bean>

<bean name="myEmployeeService" class="com.journaldev.spring.service.MyEmployeeService"
		init-method="init" destroy-method="destroy">
	<property name="employee" ref="employee"></property>
</bean>

<!-- initializing CommonAnnotationBeanPostProcessor is same as context:annotation-config -->
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
<bean name="myService" class="com.journaldev.spring.service.MyService" />
</beans>

Notice that I am not initializing employee name in it’s bean definition. Since EmployeeService is using interfaces, we don’t need any special configuration here.

For MyEmployeeService bean, we are using init-method and destroy-method attributes to let spring framework know our custom methods to execute.

MyService bean configuration doesn’t have anything special, but as you can see that I am enabling annotation based configuration for this.

Our application is ready, let’s write a test program to see how different methods get executed.

Spring Bean Life Cycle – Test Program


package com.journaldev.spring.main;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.journaldev.spring.service.EmployeeService;
import com.journaldev.spring.service.MyEmployeeService;

public class SpringMain {

	public static void main(String[] args) {
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");

		System.out.println("Spring Context initialized");
		
		//MyEmployeeService service = ctx.getBean("myEmployeeService", MyEmployeeService.class);
		EmployeeService service = ctx.getBean("employeeService", EmployeeService.class);

		System.out.println("Bean retrieved from Spring Context");
		
		System.out.println("Employee Name="+service.getEmployee().getName());
		
		ctx.close();
		System.out.println("Spring Context Closed");
	}

}

When we run above test program, we get below output.


Apr 01, 2014 10:50:50 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@c1b9b03: startup date [Tue Apr 01 22:50:50 PDT 2014]; root of context hierarchy
Apr 01, 2014 10:50:50 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring.xml]
EmployeeService no-args constructor called
EmployeeService initializing to dummy value
MyEmployeeService no-args constructor called
MyEmployeeService initializing to dummy value
MyService no-args constructor called
MyService init method called
Spring Context initialized
Bean retrieved from Spring Context
Employee Name=Pankaj
Apr 01, 2014 10:50:50 PM org.springframework.context.support.ClassPathXmlApplicationContext doClose
INFO: Closing org.springframework.context.support.ClassPathXmlApplicationContext@c1b9b03: startup date [Tue Apr 01 22:50:50 PDT 2014]; root of context hierarchy
MyService destroy method called
MyEmployeeService Closing resources
EmployeeService Closing resources
Spring Context Closed

Spring Bean Life Cycle Important Points:

  • From the console output it’s clear that Spring Context is first using no-args constructor to initialize the bean object and then calling the post-init method.
  • The order of bean initialization is same as it’s defined in the spring bean configuration file.
  • The context is returned only when all the spring beans are initialized properly with post-init method executions.
  • Employee name is printed as “Pankaj” because it was initialized in the post-init method.
  • When context is getting closed, beans are destroyed in the reverse order in which they were initialized i.e in LIFO (Last-In-First-Out) order.

You can uncomment the code to get bean of type MyEmployeeService and confirm that output will be similar and follow all the points mentioned above.

Spring Aware Interfaces

Sometimes we need Spring Framework objects in our beans to perform some operations, for example reading ServletConfig and ServletContext parameters or to know the bean definitions loaded by the ApplicationContext. That’s why spring framework provides a bunch of *Aware interfaces that we can implement in our bean classes.

org.springframework.beans.factory.Aware is the root marker interface for all these Aware interfaces. All of the *Aware interfaces are sub-interfaces of Aware and declare a single setter method to be implemented by the bean. Then spring context uses setter-based dependency injection to inject the corresponding objects in the bean and make it available for our use.

Spring Aware interfaces are similar to servlet listeners with callback methods and implementing observer design pattern.

Some of the important Aware interfaces are:

  • ApplicationContextAware – to inject ApplicationContext object, example usage is to get the array of bean definition names.
  • BeanFactoryAware – to inject BeanFactory object, example usage is to check scope of a bean.
  • BeanNameAware – to know the bean name defined in the configuration file.
  • ResourceLoaderAware – to inject ResourceLoader object, example usage is to get the input stream for a file in the classpath.
  • ServletContextAware – to inject ServletContext object in MVC application, example usage is to read context parameters and attributes.
  • ServletConfigAware – to inject ServletConfig object in MVC application, example usage is to get servlet config parameters.

Let’s see these Aware interfaces usage in action by implementing few of them in a class that we will configure as spring bean.


package com.journaldev.spring.service;

import java.util.Arrays;

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.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;

public class MyAwareService implements ApplicationContextAware,
		ApplicationEventPublisherAware, BeanClassLoaderAware, BeanFactoryAware,
		BeanNameAware, EnvironmentAware, ImportAware, ResourceLoaderAware {

	@Override
	public void setApplicationContext(ApplicationContext ctx)
			throws BeansException {
		System.out.println("setApplicationContext called");
		System.out.println("setApplicationContext:: Bean Definition Names="
				+ Arrays.toString(ctx.getBeanDefinitionNames()));
	}

	@Override
	public void setBeanName(String beanName) {
		System.out.println("setBeanName called");
		System.out.println("setBeanName:: Bean Name defined in context="
				+ beanName);
	}

	@Override
	public void setBeanClassLoader(ClassLoader classLoader) {
		System.out.println("setBeanClassLoader called");
		System.out.println("setBeanClassLoader:: ClassLoader Name="
				+ classLoader.getClass().getName());
	}

	@Override
	public void setResourceLoader(ResourceLoader resourceLoader) {
		System.out.println("setResourceLoader called");
		Resource resource = resourceLoader.getResource("classpath:spring.xml");
		System.out.println("setResourceLoader:: Resource File Name="
				+ resource.getFilename());
	}

	@Override
	public void setImportMetadata(AnnotationMetadata annotationMetadata) {
		System.out.println("setImportMetadata called");
	}

	@Override
	public void setEnvironment(Environment env) {
		System.out.println("setEnvironment called");
	}

	@Override
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		System.out.println("setBeanFactory called");
		System.out.println("setBeanFactory:: employee bean singleton="
				+ beanFactory.isSingleton("employee"));
	}

	@Override
	public void setApplicationEventPublisher(
			ApplicationEventPublisher applicationEventPublisher) {
		System.out.println("setApplicationEventPublisher called");
	}

}

Spring *Aware Example Configuration File

Very simple spring bean configuration file.


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

<bean name="employee" class="com.journaldev.spring.bean.Employee" />

<bean name="myAwareService" class="com.journaldev.spring.service.MyAwareService" />

</beans>

Spring *Aware Test Program


package com.journaldev.spring.main;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.journaldev.spring.service.MyAwareService;

public class SpringAwareMain {

	public static void main(String[] args) {
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring-aware.xml");

		ctx.getBean("myAwareService", MyAwareService.class);
		
		ctx.close();
	}

}

Now when we execute above class, we get following output.


Apr 01, 2014 11:27:05 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@60a2f435: startup date [Tue Apr 01 23:27:05 PDT 2014]; root of context hierarchy
Apr 01, 2014 11:27:05 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring-aware.xml]
setBeanName called
setBeanName:: Bean Name defined in context=myAwareService
setBeanClassLoader called
setBeanClassLoader:: ClassLoader Name=sun.misc.Launcher$AppClassLoader
setBeanFactory called
setBeanFactory:: employee bean singleton=true
setEnvironment called
setResourceLoader called
setResourceLoader:: Resource File Name=spring.xml
setApplicationEventPublisher called
setApplicationContext called
setApplicationContext:: Bean Definition Names=[employee, myAwareService]
Apr 01, 2014 11:27:05 PM org.springframework.context.support.ClassPathXmlApplicationContext doClose
INFO: Closing org.springframework.context.support.ClassPathXmlApplicationContext@60a2f435: startup date [Tue Apr 01 23:27:05 PDT 2014]; root of context hierarchy

Console output of the test program is simple to understand, I won’t go into much detail about that.

That’s all for the Spring Bean Life Cycle methods and injecting framework specific objects into the spring beans. Please download sample project from below link and analyze it to learn more about them.

Comments

  1. Seema says:

    Hi Pankaj,
    This is very nice article explain very well.
    Thanks for your contribution for sharing this knowledge with us.

  2. K Prashanth says:

    Thanks Pankaj.. clearly and very nicely explained.

  3. Monir says:

    @Pankaj,
    Very special thanks for a details about bean scope.
    What is the best way to contact you?

  4. Tony says:

    Hi Pankaj, excellent… , thank you so much for the detailed tutorial

  5. Selva says:

    Great article !

  6. kanchan tiwari says:

    Great explanation !!! thanks for the guide..

  7. Mengying Ye says:

    Thanks for your post, it’s really great ,could I translate it into chinese?

  8. shripad says:

    Nice article…and thanks for such a nice description !!! 🙂

    1. Pankaj says:

      Thanks Shri for nice words.

  9. Pranita says:

    Hi Sir,

    Thanks for this ultimate post. Once any one read this article, no need to visit any other tutorial.

    1. Pankaj says:

      Thanks for the nice words Pranita.

  10. Jagadeesh says:

    Excellent Pakaj.. Good Job..

    1. Pankaj says:

      Thanks Jagadeesh, appreciate your kind word.

  11. DR says:

    Thanks For all the tutorials

    1. Pankaj says:

      you are welcome buddy.

  12. anil says:

    Thank you sir…………

  13. Raju.m says:

    Hi pankaj,
    This is very interesting to note all point .can u pls share me spring qeb service in soap . Thanks in advance

    1. Pankaj says:

      I have written a lot on soap web services, spring don’t support SOAP web services, they provide support for REST web services. I have written about them in detail, please search and read. 🙂

  14. Vishal Upadhyay says:

    A good explanation.

  15. Ganesh says:

    Thanx sir…..

    1. Pankaj says:

      You are welcome Ganesh.

  16. johnybasha shaik says:

    Hi Pankaj.. I regularly follow your website. You are doing a great job for all the followers of this site in learing java/j2ee. I have a suggestion. Though the content you are publishing is very good and with in depth analysis. The way the articles structured are not user friendly. I mean to say. the articles are not as per index. For example, if I go to design patterns, user can’t see which list goes under creational patterns and which does go to behavioural unless I open and read each pattern. If I come to spring tutorial, I dont know which article should I start first. My suggestion, is please publish them in a sequential order to make reading user friendly. I hope you take this advice positively.
    Thanks.

    1. Pankaj says:

      Thanks for the feedback. Usually when I am done with a topic, I write a summary post with the order of articles to read.

      For example summary post for design patterns: https://www.journaldev.com/1827/java-design-patterns-example-tutorial
      Summary post for Struts2: https://www.journaldev.com/2310/struts2-tutorial-with-example-projects

      Including all the links in every post is cumbersome and not a good idea too. Imagine you start reading a post and half of the page is with 20 link to other articles. I will write a summary post for Spring Tutorial too once I am done with most of the articles in the series.

Leave a Reply

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

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages