🔹 What is the Spring Bean Lifecycle?
💡 Spring Beans go through multiple phases: creation, initialization, usage, and destruction.
💡 Spring provides hooks to customize these phases (e.g., @PostConstruct
, @PreDestroy
).
📌 Phases of the Spring Bean Lifecycle
🔥 Step by Step Breakdown:
1️⃣ Bean Instantiation → Spring creates the bean instance.
2️⃣ Populate Properties (Dependency Injection) → Spring injects dependencies.
3️⃣ Bean Name is Set (BeanNameAware#setBeanName()
)
4️⃣ Bean Factory is Set (BeanFactoryAware#setBeanFactory()
)
5️⃣ ApplicationContext is Set (ApplicationContextAware#setApplicationContext()
)
6️⃣ Before Initialization Processing (BeanPostProcessor#postProcessBeforeInitialization()
)
7️⃣ Custom Initialization Methods:
InitializingBean#afterPropertiesSet()
@PostConstruct
-
init-method
(if specified in XML or@Bean
)
8️⃣ After Initialization Processing (BeanPostProcessor#postProcessAfterInitialization()
)
9️⃣ Bean is Ready for Use! 🚀
🔟 Before Destruction Processing (DestructionAwareBeanPostProcessor#postProcessBeforeDestruction()
)
1️⃣1️⃣ Custom Destruction Methods:
DisposableBean#destroy()
@PreDestroy
-
destroy-method
(if specified in XML or@Bean
)
1️⃣2️⃣ Bean is Removed (Garbage Collected).
🔥 This entire process is controlled by Spring’s ApplicationContext
!
📌 Hands-On Project: Bean Lifecycle in Action
💡 Let’s create a small Spring Boot app to observe and control the Bean Lifecycle.
Step 1: Create a Spring Boot Project
1️⃣ Go to Spring Initializr
2️⃣ Select:
- Spring Boot Version: Latest stable
- Dependencies: Spring Web
- Packaging: Jar 3️⃣ Click Generate and extract the zip file.
Step 2: Define a Bean with Lifecycle Hooks
📌 Create a Pirate
Bean with Lifecycle Annotations:
package com.example.lifecycle;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.stereotype.Component;
@Component
public class Pirate {
public Pirate() {
System.out.println("⚓ Pirate Bean Instantiated!");
}
@PostConstruct
public void prepareForSailing() {
System.out.println("🏴☠️ @PostConstruct: Pirate is ready for adventure!");
}
@PreDestroy
public void retireFromSailing() {
System.out.println("☠️ @PreDestroy: Pirate is retiring...");
}
}
💡 What happens here?
✅ Pirate()
→ Constructor is called (bean instantiation).
✅ @PostConstruct
→ Called after dependencies are injected but before the bean is used.
✅ @PreDestroy
→ Called before the bean is destroyed (removed from context).
Step 3: Add BeanPostProcessor to Track Lifecycle Events
📌 Create a PirateLifecycleLogger
to observe Spring’s lifecycle hooks:
package com.example.lifecycle;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class PirateLifecycleLogger implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("⏳ Before Initialization: " + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("✅ After Initialization: " + beanName);
return bean;
}
}
💡 What happens here?
✅ postProcessBeforeInitialization()
runs before @PostConstruct
and afterPropertiesSet()
.
✅ postProcessAfterInitialization()
runs after initialization but before usage.
Step 4: Create the Main Application Class
📌 Modify SpringBootApplication
to trigger the lifecycle:
package com.example.lifecycle;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class LifecycleApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(LifecycleApplication.class, args);
System.out.println("🛳️ Application is Running...");
// Close context to trigger @PreDestroy
context.close();
}
}
💡 Why context.close()
?
✅ It manually shuts down the Spring application, triggering @PreDestroy
!
Step 5: Run the Application
💡 Run the app using:
mvn spring-boot:run
or
./mvnw spring-boot:run
👀 Expected Output:
⚓ Pirate Bean Instantiated!
⏳ Before Initialization: pirate
🏴☠️ @PostConstruct: Pirate is ready for adventure!
✅ After Initialization: pirate
🛳️ Application is Running...
☠️ @PreDestroy: Pirate is retiring...
🔥 Boom! You just witnessed the Spring Bean Lifecycle in action!
📌 Summary of Step 3
✅ Spring Beans have a lifecycle controlled by ApplicationContext
.
✅ Spring calls lifecycle methods like @PostConstruct
and @PreDestroy
.
✅ BeanPostProcessor
allows custom pre/post-initialization logic.
✅ context.close()
manually triggers destruction lifecycle.
📌 Topics Covered in This Section
📜 Spring Bean Lifecycle (✔️ Covered)
How Beans are created & destroyed (Instantiation → Initialization → Destruction).
-
Lifecycle methods:
- @PostConstruct (Runs after properties are set).
- @PreDestroy (Runs before bean destruction).
-
BeanPostProcessor Hooks:
- postProcessBeforeInitialization()
- postProcessAfterInitialization()
Manually closing the ApplicationContext (context.close()).
🔥 Key Takeaways to Remember:
✅ Spring manages bean lifecycles automatically using ApplicationContext.
✅ @PostConstruct and @PreDestroy are commonly used for lifecycle management.
✅ BeanPostProcessor allows customization before/after initialization.
✅ Manually closing the ApplicationContext triggers @PreDestroy.