A comprehensive demonstration of Spring Bean Lifecycle using manual method implementations in Java.
This project demonstrates the complete lifecycle of a Spring Bean by implementing various lifecycle interfaces and callbacks. It shows how Spring manages beans from creation to destruction, providing hooks at each stage for custom initialization and cleanup logic.
The Spring Bean Lifecycle refers to the series of stages a bean goes through from its instantiation to its destruction. Spring provides multiple ways to hook into this lifecycle, allowing developers to execute custom code at specific points.
1. Bean Instantiation
2. Populate Properties
3. BeanNameAware's setBeanName()
4. BeanFactoryAware's setBeanFactory()
5. ApplicationContextAware's setApplicationContext()
6. BeanPostProcessor's postProcessBeforeInitialization()
7. InitializingBean's afterPropertiesSet()
8. Custom init-method
9. BeanPostProcessor's postProcessAfterInitialization()
↓
[Bean Ready for Use]
↓
10. @PreDestroy annotation method
11. DisposableBean's destroy()
12. Custom destroy-method
sh.surge.kunal.banking/
├── configurations/
│ ├── AppConfig.java # Spring configuration with bean definitions
│ └── CustomerBeanPostProcessor.java # Custom BeanPostProcessor implementation
├── models/
│ ├── Address.java # Address model
│ ├── Customer.java # Main bean demonstrating lifecycle
│ └── FullName.java # FullName model
└── utils/
└── CustomerApp.java # Application entry point
The Customer class implements multiple Spring lifecycle interfaces to demonstrate each stage:
- BeanNameAware: Receives the bean name from the container
- BeanFactoryAware: Gets access to the BeanFactory
- ApplicationContextAware: Gets access to the ApplicationContext
- InitializingBean: Executes initialization logic after properties are set
- DisposableBean: Executes cleanup logic before bean destruction
// Step 1: Bean Name Awareness
@Override
public void setBeanName(String name) {
logger.info("1. Bean Name is set in Customer Bean: " + name);
}
// Step 2: Bean Factory Awareness
@Override
public void setBeanFactory(BeanFactory beanFactory) {
logger.info("2. Bean Factory is set in Customer Bean");
}
// Step 3: Application Context Awareness
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
logger.info("3. Application Context is set in Customer Bean");
}
// Step 4: After Properties Set
@Override
public void afterPropertiesSet() {
logger.info("4. Customer Bean is initialized");
}
// Step 5: Custom Init Method
public void customInit() {
logger.info("5. Custom Init method called for Customer Bean");
}
// Step 6: Pre Destroy
@PreDestroy
public void preDestroy() {
logger.info("6. Pre Destroy method called for Customer Bean");
}
// Step 7: Destroy Interface
@Override
public void destroy() {
logger.info("7. Customer Bean is destroyed");
}
// Step 8: Custom Destroy Method
public void customDestroy() {
logger.info("8. Custom Destroy method called for Customer Bean");
}Defines the Customer bean with custom init and destroy methods:
@Bean(initMethod = "customInit", destroyMethod = "customDestroy")
public Customer customer() {
// Bean creation with Faker library for dummy data
Faker faker = new Faker();
Customer customer = new Customer();
// ... property initialization
return customer;
}Intercepts bean initialization to add custom logic before and after initialization:
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if(bean instanceof Customer) {
logger.info("Customer Bean is about to be initialized: " + beanName);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if(bean instanceof Customer) {
logger.info("Customer Bean has been initialized: " + beanName);
}
return bean;
}Demonstrates the complete lifecycle by creating and closing the application context:
// Create context - triggers bean creation and initialization
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
// Get and use the bean
Customer customer = context.getBean(Customer.class);
logger.info("Customer Details: " + customer);
// Close context - triggers bean destruction
context.close();- Ensure you have Java 17+ and Maven installed
- Run the
CustomerApp.javaclass - Observe the console output showing the complete bean lifecycle
1. Bean Name is set in Customer Bean: customer
2. Bean Factory is set in Customer Bean
3. Application Context is set in Customer Bean
Customer Bean is about to be initialized: customer
4. Customer Bean is initialized
5. Custom Init method called for Customer Bean
Customer Bean has been initialized: customer
Customer Details: [Customer object details]
6. Pre Destroy method called for Customer Bean
7. Customer Bean is destroyed
8. Custom Destroy method called for Customer Bean
- Lifecycle Interfaces: BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean
- Custom Callbacks: init-method and destroy-method attributes
- Annotations: @PreDestroy for pre-destruction callbacks
- BeanPostProcessor: Custom processing before and after initialization
- Configuration: Java-based configuration with @Configuration and @Bean
- Spring Framework (Core, Context, Beans)
- Lombok (for reducing boilerplate code)
- JavaFaker (for generating test data)
- SLF4J (for logging)
This pattern is useful for:
- Resource initialization (database connections, file handles)
- Configuration validation
- Resource cleanup and connection closing
- Custom logging and monitoring
- Cache warming
- External service initialization
- All lifecycle methods are called in a specific order by the Spring container
- BeanPostProcessor methods are called for all beans in the container
- Custom init/destroy methods can have any name but must be specified in @Bean annotation
- @PreDestroy is called before DisposableBean.destroy()
Author: Kunal
Purpose: Educational demonstration of Spring Bean Lifecycle