DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Smart Dependency Injection With Spring: Assignability (Part 2 of 3)
  • Spring Beans With Auto-Generated Implementations: How-To
  • The Magic of Spring Data
  • Spring Boot Centralized Logging with Graylog

Trending

  • Designing a Java Connector for Software Integrations
  • Unit Testing Large Codebases: Principles, Practices, and C++ Examples
  • Modern Test Automation With AI (LLM) and Playwright MCP
  • Event-Driven Microservices: How Kafka and RabbitMQ Power Scalable Systems
  1. DZone
  2. Coding
  3. Frameworks
  4. Spring Bean Lifecycle

Spring Bean Lifecycle

Check out this post to learn more about the Spring bean lifecycle.

By 
John Thompson user avatar
John Thompson
·
Sep. 19, 19 · Presentation
Likes (27)
Comment
Save
Tweet
Share
92.4K Views

Join the DZone community and get the full member experience.

Join For Free

Spring (Coffee) Bean lifecycle

Spring (Coffee) Bean Lifecycle

The Spring IoC (Inversion of Control) container manages Spring beans. A “Spring bean” is just a Spring-managed instantiation of a Java class.

The Spring IoC container is responsible for instantiating, initializing, and wiring beans. The container also manages the life cycle of beans.

Spring provides several ways through which you can tap into the bean lifecycle. For example, once a bean is instantiated, you might need to perform some initialization to get the bean into a usable state. Similarly, you might need to clean up resources before a bean is removed from the container.

In this post, we will examine the steps of Spring bean lifecycle. This is how the Spring Framework creates and destroys Spring beans.

Spring Bean Lifecycle Overview

The figure below shows two parts of the Spring bean lifecycle:

Part 1: Shows the different stages a bean goes through after instantiation until it is ready for use.
Part 2: Shows what happens to a bean once the Spring IoC container shuts down.

As you can see in Part 1 of the preceding figure, the container instantiates a bean by calling its constructor and then populates its properties.

This is followed by several calls to the bean until the bean is in the ready state.

Similarly, as shown in Part 2, when the container shuts down, the container calls the bean to enable it to perform any required tasks before the bean is destroyed.

Aware Interfaces

Spring provides several aware interfaces. These are used to access the Spring Framework infrastructure. The aware interfaces are largely used within the framework and rarely used by Spring programmers.

You as Spring programmers should be familiar with the following three aware interfaces.

  • BeanFactoryAware: Provides setBeanFactory(), a callback that supplies the owning factory to the bean instance.
  • BeanNameAware: ThesetBeanName() callback of this interface supplies the name of the bean.
  • ApplicationContextAware: ThesetApplicationContext() method of this interface provides the ApplicationContext object of this bean.

The code to use the preceding aware interfaces is this.

package guru.springframework.springbeanlifecycle.awareinterfaces.domain;
import org.springframework.beans.BeansException;
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 java.util.Arrays;
public class AwareBeanImpl implements ApplicationContextAware, BeanNameAware, BeanFactoryAware {
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("setBeanFactory method of AwareBeanImpl is called");
System.out.println("setBeanFactory:: AwareBeanImpl singleton= "
+ beanFactory.isSingleton("awareBean"));
}
@Override
public void setBeanName(String beanName) {
System.out.println("setBeanName method of AwareBeanImpl is called");
System.out.println("setBeanName:: Bean Name defined in context= "
+ beanName);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("setApplicationContext method of AwareBeanImpl is called");
System.out.println("setApplicationContext:: Bean Definition Names= "
+ Arrays.toString(applicationContext.getBeanDefinitionNames()));
}
}


The preceding bean implements the ApplicationContextAware, BeanNameAware, and BeanFactoryAware interfaces. In the preceding code:

Line 13 – Line 18: The code overrides the setBeanFactory() method of the BeanFactoryAware interface. During runtime, Spring passes the BeanFactory object that created the bean. The code uses the BeanFactory object to print whether or not this bean is a singleton.

Line 20 – Line 25 overrides the setBeanName() method of the BeanNameAware interface. During runtime, Spring passes the name of the bean as a String that the code prints out. The code uses the beanName to print the bean name defined in context.

In Line 27 – Line 32, the code overrides the setApplicationContext() method of the ApplicationContextAware interface. During runtime, Spring passes the ApplicationContext object that created the bean. The code uses the ApplicationContext object to print the bean definition names.

Next, we will write the bean configuration to define the AwareBeanImpl. The code of the beans.xml is this.

<?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-3.0.xsd">
   <!--    awareinterfaces-->
   <bean id="awareBean" class="guru.springframework.springbeanlifecycle.awareinterfaces.domain.AwareBeanImpl">
   </bean>
</beans>


Finally, let us write the main class, which will load the beans.xml and test the aware interface methods.

package guru.springframework.springbeanlifecycle;
import guru.springframework.springbeanlifecycle.awareinterfaces.domain.AwareBeanImpl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@SpringBootApplication
public class SpringBeanLifecycleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBeanLifecycleApplication.class, args);
// -------awareinterfaces---------
ApplicationContext context1 =
new ClassPathXmlApplicationContext("beans.xml");
AwareBeanImpl awareBeanImpl = (AwareBeanImpl) context1.getBean("awareBean");
((AbstractApplicationContext) context1).registerShutdownHook();
}
}


The output on running the main class is this:

setBeanName method of AwareBeanImpl is called
setBeanName:: Bean Name defined in context= awareBean
setBeanFactory method of AwareBeanImpl is called
setBeanFactory:: AwareBeanImpl singleton= true
setApplicationContext method of AwareBeanImpl is called
setApplicationContext:: Bean Definition Names= [awareBean]


Bean Post Processor

Spring provides the BeanPostProcessor interface that gives you the means to tap into the Spring context lifecycle and interact with beans as they are processed.

The BeanPostProcessor interface contains two methods:

  • postProcessBeforeInitialization: Spring calls this method after calling the methods of the aware interfaces and before any bean initialization callbacks, such as  InitializingBean’s afterPropertiesSet or a custom init-method.
  • postProcessAfterInitialization: Spring calls this method after any bean initialization callbacks.

Let us start by creating a bean, named BookBean.

package guru.springframework.springbeanlifecycle.beanpostprocessor.domain;
public class BookBean {
private String bookName;
public BookBean() {
System.out.println("Constructor of BookBean called !! ");
}
public BookBean(String bookName) {
this.bookName = bookName;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
@Override
public String toString() {
return "BookBean{" +
"bookName='" + bookName + '\'' +
'}';
}
}


Next, we will create the BookBeanPostProcessor.

The code for BookBeanPostProcessor is this:

package guru.springframework.springbeanlifecycle.beanpostprocessor.domain;
import guru.springframework.springbeanlifecycle.beanpostprocessor.domain.BookBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class BookBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Post Process Before Initialization method is called : Bean Name " + beanName);
return bean; }
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Post Process After Initialization method is called : Bean Name " + beanName);
return bean;
}
}


The preceding code implements the BeanPostProcessor interface and overrides the postProcessBeforeInitialization() and postProcessAfterInitialization()  methods.

Spring calls the postProcessBeforeInitialization() method after calling the methods of the aware interfaces.

Spring calls the postProcessAfterInitialization() method after any bean initialization callbacks, such as  InitializingBean’s afterPropertiesSet or a custom init-method. We will discuss both going ahead.

At runtime, Spring will inject the new bean instance and the name of the bean to both the methods.

Next, we will define BookBean and BookBeanProcessor as beans in the XML configuration.

The configuration code is this.

<?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-3.0.xsd">
<bean id="bookBeanPost" class="guru.springframework.springbeanlifecycle.beanpostprocessor.domain.BookBean">
<property name="bookName" value="Gone with the Wind"></property>
</bean>
<bean id="bookBeanPostProcessor"
class="guru.springframework.springbeanlifecycle.beanpostprocessor.domain.BookBeanPostProcessor"/>
</beans>


The main class to test our BeanPostProcessor is this.

package guru.springframework.springbeanlifecycle;
import guru.springframework.springbeanlifecycle.beanpostprocessor.domain.BookBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@SpringBootApplication
public class SpringBeanLifecycleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBeanLifecycleApplication.class, args);
// -------beanpostprocessor------
ApplicationContext context4 =
new ClassPathXmlApplicationContext("beans.xml");
BookBean bookBean = (BookBean) context4.getBean("bookBeanPost");
((AbstractApplicationContext) context4).registerShutdownHook();
}
}


The output on running the main class is this.

  • Constructor of BookBean called !!
  • Post Process After Initialization method is called: Bean Name bookBeanPost
  • Post Process Before Initialization method is called: Bean Name bookBeanPost

InitializingBean and DisposableBean Callback Interfaces

Spring provides the following two callback interfaces:

  • InitializingBean: Declares the afterPropertiesSet() method which can be used to write the initialization logic. The container calls the method after properties are set.
  • DisposableBean: Declares the destroy() method which can be used to write any clean up code. The container calls this method during bean destruction in shutdown.

Let’s write a bean that implements the InitalizingBean and DisposableBean interfaces.

The code of the Book bean is this.

package guru.springframework.springbeanlifecycle.callbackinterfaces.domain;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class Book implements InitializingBean, DisposableBean {
private String bookName;
public Book() {
System.out.println("Constructor of Book bean is called !! ");
}
@Override
public void destroy() throws Exception {
System.out.println("Destroy method of Book bean called !! ");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet method of Book bean is called !! ");
}
public Book(String bookName) {
this.bookName = bookName;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
@Override
public String toString() {
return "Book{" +
"bookName='" + bookName + '\'' +
'}';
}
}


The preceding Book bean implements the InitializingBean and DisposableBean interfaces and overrides their afterPropertiesSet() and destroy() method.

Next, we will write the bean configuration to define the Book bean.

The code of the beans.xml file is this.

<?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-3.0.xsd">
<!-- callbackinterfaces-->
<bean id="bookBean" class="guru.springframework.springbeanlifecycle.callbackinterfaces.domain.Book">
<property name="bookName" value="Believe in Yourself"/>
</bean>
</beans>


The main class is this.

package guru.springframework.springbeanlifecycle;
import guru.springframework.springbeanlifecycle.callbackinterfaces.domain.Book;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@SpringBootApplication
public class SpringBeanLifecycleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBeanLifecycleApplication.class, args);
// -------callbackinterfaces-------
ApplicationContext context =
new ClassPathXmlApplicationContext("beans.xml");
Book book = (Book) context.getBean("bookBean");
System.out.println(book.getBookName());
((AbstractApplicationContext) context).registerShutdownHook();
}
}


The preceding code retrieves the Book bean from the ApplicationContext and prints out the value of the bookName property.

The output on running the main class is this.

  • The constructor of Book bean is called !!
  • afterPropertiesSet method of Book bean is called !!
  • Believe in Yourself
  • destroy method of Book bean is called !!

As you can note in the output, the afterPropertiesSet() method got called first.

Custom Init and Destroy Method

While declaring bean in XML configuration, you can specify the init-method and destroy-method attributes in the tag. Both the attributes specify custom methods in the bean class.

The method declared in the init-method attribute is called after Spring initializes bean properties through setter or constructor arguments. You can use this method to validate the injected properties or perform any other tasks.

Spring calls the method declared in the destroy-method attribute just before the bean is destroyed.

Let’s use the custom init and destroy methods in a bean, named BookCustomBean.

The code for BookCustomBean is this.

package guru.springframework.springbeanlifecycle.custominitanddestroy.domain;
public class BookCustomBean {
private String bookName;
public BookCustomBean() {
System.out.println("Constructor of BookCustomBean bean is called !! ");
}
public void customDestroy() throws Exception {
System.out.println("Custom destroy method of BookCustomBean called !! ");
}
public void customInit() throws Exception {
System.out.println("Custom Init method of BookCustomBean called !! ");
}
public BookCustomBean(String bookName) {
this.bookName = bookName;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
@Override
public String toString() {
return "Book{" +
"bookName='" + bookName + '\'' +
'}';
}
}


In the preceding code, customInit and customDestroy are regular methods that prints output messages.

Next, we’ll write the bean configuration, beans.xml.

<?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-3.0.xsd">
<!-- Declare custom init and destroy methods-->
<bean id="customLifeCycleBookBean"
class="guru.springframework.springbeanlifecycle.custominitanddestroy.domain.BookCustomBean"
init-method="customInit"
destroy-method="customDestroy">
<property name="bookName" value="Life and Laughing"></property>
</bean>
</beans>


In the preceding code, Line 11 – Line 12 uses the init-method and destroy-method attributes with the values customInit and customDestroy.

The code of the main class is this.

package guru.springframework.springbeanlifecycle;
import guru.springframework.springbeanlifecycle.custominitanddestroy.domain.BookCustomBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@SpringBootApplication
public class SpringBeanLifecycleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBeanLifecycleApplication.class, args);
// -------custominitanddestroy------
ApplicationContext context3 =
new ClassPathXmlApplicationContext("beans.xml");
BookCustomBean bookCustomBean = (BookCustomBean) context3.getBean("customLifeCycleBookBean");
((AbstractApplicationContext) context3).registerShutdownHook();
}
}


The preceding code loads the XML configuration and tests the init-method and destroy-method.

The output on running the preceding code is this.

  • Constructor of BookCustomBean bean is called !!
  • Custom Init method of BookCustomBean called !!
  • Custom destroy method of BookCustomBean called !!

Summary

All Spring beans go through a specific lifecycle, and as we have seen, there’s actually a lot that goes on under the hood. Most of this is handled by the framework, and as a Spring developer, you will seldom require to get into it that often. However, as you get into more and more complex applications with the Spring Framework, at times, you have to be aware of what goes on during a bean lifecycle.

I personally don’t prefer using the InitializingBean and DisposableBean interfaces. Primarily because it tightly couples your code to Spring. A better approach is specifying the init-method and destroy-method attributes in your bean configuration file.

Further Reading

Spring Bean Lifecycle: Using Spring Aware Interfaces

[DZone Refcard] Spring Configuration

Spring Framework Interface (computing)

Published at DZone with permission of John Thompson, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Smart Dependency Injection With Spring: Assignability (Part 2 of 3)
  • Spring Beans With Auto-Generated Implementations: How-To
  • The Magic of Spring Data
  • Spring Boot Centralized Logging with Graylog

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!