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:
- Instantiation – Bean object is created.
- Populate Properties – Dependencies are injected (via constructor or setter injection).
- Bean Name Awareness – Bean can be made aware of its name.
- Bean Factory Awareness – Bean can interact with BeanFactory.
- Application Context Awareness – Bean can access ApplicationContext.
- Pre-initialization Processing – Before initialization hook.
- Initialization – Custom initialization logic is executed.
- Post-initialization Processing – After initialization hook.
- Usage – Bean is ready to be used in the application.
- 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"); }