DEV Community

nk sk
nk sk

Posted on

🌱 Understanding the Spring Bean Lifecycle

In the Spring Framework, beans are the backbone of any application. They represent the objects that Spring manages inside its IoC (Inversion of Control) container.
To truly harness Spring’s power, it’s important to understand how beans are created, initialized, and destroyed β€” in other words, their lifecycle.


πŸ”„ The Bean Lifecycle in Spring

When you declare a bean using annotations (@Component) or configuration (@Bean), Spring takes full control over it.
Here’s the typical lifecycle flow:

  1. Bean Instantiation
    Spring creates the bean instance (via constructor or factory method).

  2. Dependency Injection
    Required dependencies are injected into the bean’s fields, setters, or constructors.

  3. Aware Interfaces (Optional)
    If your bean implements aware interfaces, Spring provides additional context:

  • BeanNameAware β†’ gives the bean’s name.
  • BeanFactoryAware β†’ gives access to the bean factory.
  • ApplicationContextAware β†’ gives access to the application context.
  1. BeanPostProcessor – Before Initialization
    Any registered BeanPostProcessor can manipulate the bean before initialization.

  2. Initialization Phase

  • If the bean implements InitializingBean, the afterPropertiesSet() method is called.
  • If the bean defines an init method, Spring calls it.
  • If annotated with @PostConstruct, that method executes here.
  1. BeanPostProcessor – After Initialization
    Beans may be wrapped or enhanced after initialization (e.g., proxy creation for AOP).

  2. Bean Ready for Use
    At this stage, the bean is fully initialized and can be used within the application.

  3. Destruction Phase
    When the application context is closed:

  • If the bean implements DisposableBean, the destroy() method runs.
  • Any @PreDestroy methods or custom destroy methods are executed.

βœ… Lifecycle Hook Options

Spring provides multiple ways to plug into this lifecycle.

1. Using @PostConstruct and @PreDestroy (Modern & Recommended)

@Component
public class MyBean {

    @PostConstruct
    public void init() {
        System.out.println("Bean initialized: resources opened");
    }

    @PreDestroy
    public void cleanup() {
        System.out.println("Bean destroyed: resources released");
    }
}
Enter fullscreen mode Exit fullscreen mode

2. Using InitializingBean and DisposableBean

@Component
public class MyBean implements InitializingBean, DisposableBean {

    @Override
    public void afterPropertiesSet() {
        System.out.println("afterPropertiesSet() called");
    }

    @Override
    public void destroy() {
        System.out.println("destroy() called");
    }
}
Enter fullscreen mode Exit fullscreen mode

3. Specifying Init and Destroy Methods in @Bean

@Configuration
public class AppConfig {

    @Bean(initMethod = "customInit", destroyMethod = "customDestroy")
    public MyBean myBean() {
        return new MyBean();
    }
}
Enter fullscreen mode Exit fullscreen mode
public class MyBean {
    public void customInit() {
        System.out.println("Custom init method");
    }

    public void customDestroy() {
        System.out.println("Custom destroy method");
    }
}
Enter fullscreen mode Exit fullscreen mode

4. Using BeanPostProcessor (For Cross-Cutting Concerns)

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("Before init: " + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("After init: " + beanName);
        return bean;
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸ“Š Visualizing the Lifecycle

[Instantiation] 
     ↓
[Dependency Injection]
     ↓
[Aware Interfaces]
     ↓
[BeanPostProcessor (Before Init)]
     ↓
[Init Phase β†’ @PostConstruct / afterPropertiesSet() / initMethod()]
     ↓
[BeanPostProcessor (After Init)]
     ↓
[Bean Ready for Use]
     ↓
[Destruction β†’ @PreDestroy / destroy() / destroyMethod()]
Enter fullscreen mode Exit fullscreen mode

πŸ”Ž Quick Comparison of Methods

Approach When to Use
@PostConstruct / @PreDestroy βœ… Recommended in modern Spring apps
InitializingBean / DisposableBean Useful when you want to bind directly to interfaces
initMethod / destroyMethod in @Bean Useful when you don’t control the bean class (e.g., third-party beans)
BeanPostProcessor For cross-cutting concerns (logging, proxying, monitoring)

πŸ“ Conclusion

The Spring Bean Lifecycle gives you multiple hooks to manage resources, initialize connections, and perform cleanup.

  • Use @PostConstruct and @PreDestroy for most cases.
  • Fall back on initMethod/destroyMethod for external beans.
  • Use BeanPostProcessor for advanced scenarios.

Mastering this lifecycle ensures your beans are efficient, reliable, and resource-safe throughout the lifetime of your Spring application.


Top comments (0)