ReviseAlgo Logo

Spring Fundamentals

Bean Lifecycle — How Spring Creates and Destroys Beans

The complete lifecycle phases: instantiation, populating properties, aware interfaces, post-processors, and destruction.

Interview: Crucial for understanding how to hook custom init/destroy logic, how bean post-processors intercept beans, and resolving initialization order issues.

Last Updated: June 15, 2026 15 min read

Introduction

Unlike normal Java objects that are instantiated, used, and eventually garbage collected, beans inside the Spring IoC container follow a highly structured lifecycle. The container oversees their creation, execution of configuration logic, intercepting hooks, and destruction.

Why It Matters

Understanding the bean lifecycle is critical when dealing with stateful configurations, third-party library integrations, resource pooling, or startup/shutdown routines. For instance, you might need to establish database connections or read custom parameters *after* fields have been injected but *before* the bean handles requests, or gracefully close files and sockets upon server shutdown to prevent resource leaks.

Real-World Analogy

Think of a Spring bean like a rented apartment:

  1. Construction: The developer builds the physical structure (Instantiation).
  2. Furnishing: Appliances and utilities are installed (Dependency Injection).
  3. Inspection: The city inspector walks through the unit to make sure it meets fire code (BeanPostProcessors / Aware Interfaces).
  4. Moving In: The tenant occupies the space and lives there (In Use).
  5. Moving Out: The tenant packs up, cleans the apartment, and returns the keys to the landlord (PreDestroy / Cleanup).

The Lifecycle Sequence

When a Spring application boots up, each bean passes through these sequential stages:

1
Instantiation

The container allocates memory and calls the class constructor (equivalent to new MyClass()).

2
Populate Properties

Dependency injection takes place. Fields and setters annotated with @Autowired are populated.

3
Aware Interfaces

If the bean implements Aware interfaces (e.g. BeanNameAware, BeanFactoryAware, ApplicationContextAware), Spring injects the corresponding container references.

4
BeanPostProcessor (Before Initialization)

Spring invokes the postProcessBeforeInitialization method of all registered BeanPostProcessor beans.

5
Initialization

Initial custom configurations are run. Spring triggers them in order: @PostConstruct annotations, InitializingBean.afterPropertiesSet(), and then custom initMethod declarations.

6
BeanPostProcessor (After Initialization)

Spring invokes the postProcessAfterInitialization method, which commonly wraps components in proxies (like transaction or security proxies).

7
Destruction

When the application context is closed, the bean is destroyed. Destruction callbacks run in order: @PreDestroy annotations, DisposableBean.destroy(), and custom destroyMethod declarations.

Practical Example

Here is a complete bean demonstrating all initialization and destruction methods:

Quick Quiz

Q1: Which init method is executed first in the Spring bean lifecycle?

A) Custom init-method defined in @Bean(initMethod = "...")

B) afterPropertiesSet() from InitializingBean

C) Methods annotated with @PostConstruct

D) The destroy() method

Answer: C — Spring processes modern JSR-250 annotation @PostConstruct first, followed by the InitializingBean interface, and lastly any custom XML/Java DSL configuration initMethod.

Q2: When does Spring invoke BeanPostProcessors during startup?

A) Before the constructor is called.

B) Immediately before and after the bean initialization phase.

C) Only when the bean is garbage collected.

D) When an HTTP request is received.

Answer: B — BeanPostProcessor has two callbacks: postProcessBeforeInitialization (runs before init hooks) and postProcessAfterInitialization (runs after init hooks, often creating proxies).

Scenario-Based Challenge

Production Scenario:

You want to load a configuration file from a remote location and parse it right when your service bean boots up. You attempted to put the loading logic in the constructor, but it threw a NullPointerException because the required ConfigProperties dependency was null. How would you fix this?

View Solution

At the time the constructor is called, dependency injection has not yet taken place, meaning fields are null. Put the parsing logic in a method annotated with @PostConstruct. This ensures the method is run only *after* all dependencies have been fully injected and resolved by Spring. Alternatively, use **Constructor Injection** so that the constructor is forced to take the properties object directly, allowing instantiation and loading to occur safely within the constructor itself.

Interview Questions

1. Conceptual: What is the difference between @PostConstruct and InitializingBean interface?

@PostConstruct is a standard Java annotation (JSR-250). Implementing InitializingBean requires implementing afterPropertiesSet(), which tightly couples your domain code to the Spring Framework. In modern applications, @PostConstruct is strongly preferred for keeping configurations clean.

2. Technical: How does Spring use proxies in the BeanPostProcessor phase?

During postProcessAfterInitialization, post-processors check if a bean requires transaction management (@Transactional) or security (@Secured). If it does, Spring creates a dynamic JDK proxy or CGLIB proxy class that intercepts class method calls, wrapping them in transactional or security checks, and returns this proxy bean instead of the raw instance.

Production Considerations

Use annotations (@PostConstruct and @PreDestroy) to handle simple startup and shutdown routines. For third-party beans where source code cannot be modified, define the custom routines using the initMethod and destroyMethod attributes on the @Bean annotation. Ensure that destroy methods are non-blocking to prevent long application shutdown cycles.