Learnitweb

Bean Lifecycle in Spring Boot

Spring Boot (and Spring Framework in general) manages the lifecycle of beans using the Inversion of Control (IoC) Container, which creates, configures, and manages the entire lifecycle of objects (called beans). Understanding the Bean Lifecycle is essential for developers who want to hook into certain phases of a bean’s existence, such as initialization or destruction, to perform custom logic.

1. What is a Bean in Spring Boot?

In Spring Boot, any object that is managed by the Spring container is called a bean. Beans are created, initialized, and destroyed by the Spring IoC container.

Beans are typically created using:

  • @Component, @Service, @Repository, or @Controller annotations, or
  • Defined in configuration classes using @Bean annotation.

2. Complete Bean Lifecycle Phases

The full lifecycle of a Spring bean involves multiple phases:

  1. Instantiation – Bean object is created.
  2. Populate Properties – Dependencies are injected (via constructor or setter injection).
  3. Bean Name Awareness – Bean can be made aware of its name.
  4. Bean Factory Awareness – Bean can interact with BeanFactory.
  5. Application Context Awareness – Bean can access ApplicationContext.
  6. Pre-initialization Processing – Before initialization hook.
  7. Initialization – Custom initialization logic is executed.
  8. Post-initialization Processing – After initialization hook.
  9. Usage – Bean is ready to be used in the application.
  10. Destruction – Clean-up before bean is destroyed (when context is closed).

3. Detailed Lifecycle Breakdown

Step 1: Instantiation

Spring first creates an instance of the bean using either:

  • Constructor Injection (with @Autowired constructor), or
  • Default constructor.

Step 2: Dependency Injection

Spring performs Dependency Injection by populating fields marked with @Autowired or by using constructor/setter injection.

Step 3: Bean Name Awareness

If your bean implements the BeanNameAware interface, Spring calls the setBeanName(String name) method, allowing the bean to know its name in the context.

@Component
public class MyBean implements BeanNameAware {
    @Override
    public void setBeanName(String name) {
        System.out.println("Bean name is: " + name);
    }
}

Step 4: Bean Factory Awareness

If your bean implements BeanFactoryAware, Spring injects the BeanFactory by calling setBeanFactory(BeanFactory beanFactory).

@Component
public class MyBean implements BeanFactoryAware {
    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        System.out.println("BeanFactory has been set");
    }
}

Step 5: Application Context Awareness

Beans can access the full application context by implementing ApplicationContextAware.

@Component
public class MyBean implements ApplicationContextAware {
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        System.out.println("ApplicationContext has been set");
    }
}

Step 6: Bean Post-Processing (Before Initialization)

Before the bean’s custom initialization logic runs, BeanPostProcessor can modify the bean.

@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("Before Initialization: " + beanName);
        return bean;
    }
}

Step 7: Custom Initialization

There are multiple ways to run initialization logic after properties are set:

  • @PostConstruct annotation
  • InitializingBean interface
  • initMethod in @Bean annotation

Example 1: @PostConstruct

@Component
public class MyBean {
    @PostConstruct
    public void init() {
        System.out.println("MyBean is initialized");
    }
}

Example 2: InitializingBean

@Component
public class MyBean implements InitializingBean {
    @Override
    public void afterPropertiesSet() {
        System.out.println("InitializingBean's afterPropertiesSet called");
    }
}

Example 3: initMethod in @Bean

@Bean(initMethod = "customInit")
public MyBean myBean() {
    return new MyBean();
}

public void customInit() {
    System.out.println("Custom Init Method called");
}

Step 8: Bean Post-Processing (After Initialization)

postProcessAfterInitialization() is called after initialization, again through BeanPostProcessor.

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
    System.out.println("After Initialization: " + beanName);
    return bean;
}

Step 9: Bean is Ready for Use

At this stage, the bean is fully initialized, injected with dependencies, aware of the Spring context, and ready to serve the application.

Step 10: Bean Destruction

Spring ensures that beans clean up resources when the application context is closed.

Ways to define destruction logic:

  • @PreDestroy annotation
  • DisposableBean interface
  • destroyMethod in @Bean

Example 1: @PreDestroy

@PreDestroy
public void destroy() {
    System.out.println("MyBean is about to be destroyed");
}

Example 2: DisposableBean

@Component
public class MyBean implements DisposableBean {
    @Override
    public void destroy() {
        System.out.println("DisposableBean destroy method called");
    }
}

Example 3: destroyMethod in @Bean

@Bean(destroyMethod = "customDestroy")
public MyBean myBean() {
    return new MyBean();
}

public void customDestroy() {
    System.out.println("Custom destroy method called");
}