Bean Lifecycle
Understand the complete Spring bean lifecycle — from instantiation through initialization to destruction — and how to hook into each phase for initialization and cleanup.
Last reviewed: January 2025
🔍 What Is It?
The Spring bean lifecycle is the sequence of events from when a bean is created to when it's destroyed.
Full lifecycle sequence:
- Instantiation — constructor called
- Dependency Injection — properties set, constructor/setter injection
- BeanNameAware.setBeanName() — bean learns its name
- BeanFactoryAware.setBeanFactory() — bean gets container reference
- ApplicationContextAware.setApplicationContext() — bean gets context
- BeanPostProcessor.postProcessBeforeInitialization() — pre-init processing
- @PostConstruct method called
- InitializingBean.afterPropertiesSet() — programmatic init
- @Bean(initMethod="...") — custom init method
- BeanPostProcessor.postProcessAfterInitialization() — post-init (AOP proxies created here)
- Bean is ready — in use
- @PreDestroy method called
- DisposableBean.destroy() — programmatic cleanup
- @Bean(destroyMethod="...") — custom destroy method
In practice, you only need:
- →
@PostConstructfor initialization - →
@PreDestroyfor cleanup
🎯 Why Do We Need It?
Lifecycle hooks let you:
- →Initialize resources after all dependencies are injected (cache warmup, connection validation)
- →Register listeners once the bean is fully set up
- →Clean up resources gracefully on shutdown (close connections, flush buffers)
- →Validate configuration at startup rather than at first use
Without lifecycle hooks, you'd have initialization logic in constructors (where dependencies might not be available) or scattered across the codebase.
🏗️ What Happens in Real Projects?
Common lifecycle patterns in enterprise apps:
- →
@PostConstruct: warm up caches, validate external service connectivity, start background threads - →
@PreDestroy: close database connections, flush message queues, stop schedulers - →
BeanPostProcessor: AOP proxies are created here (every@Transactionalbean goes through this) - →
ApplicationListener<ContextRefreshedEvent>: run code when ALL beans are initialized
⚙️ How It Works
@PostConstruct:
- →Runs after constructor AND after all
@Autowiredinjections are complete - →Safe to use dependencies here (unlike constructor, where DI may not be done)
- →Runs once per bean instance
- →If it throws, the application fails to start
@PreDestroy:
- →Runs when the ApplicationContext is closing
- →For web apps: triggered by JVM shutdown hook or explicit close()
- →Prototype-scoped beans: @PreDestroy is NOT called (Spring doesn't track them)
- →Runs in reverse order of initialization
BeanPostProcessor:
- →Runs for EVERY bean in the context
- →Used by Spring internally for AOP proxying, @Async, @Transactional
- →Implement BeanPostProcessor to add cross-cutting behavior to all beans
💻 Example
Bean Lifecycle in Practice — Real-world lifecycle hooks for initialization and cleanup.
🤔 Common Confusions
❓ Why can't I use dependencies in the constructor like I can in @PostConstruct?
In the constructor, Spring hasn't injected dependencies yet (for setter/field injection). By @PostConstruct time, all injection is complete. With constructor injection, dependencies ARE available in the constructor — but @PostConstruct is still better for initialization because it runs after the full bean setup, including any BeanPostProcessor processing.
❓ Is @PreDestroy called for prototype beans?
No. Spring creates prototype beans on demand but doesn't track them after creation. @PreDestroy is never called for prototype-scoped beans. If you need cleanup for prototypes, implement DisposableBean and call destroy() manually, or use a singleton factory that manages the lifecycle.
❓ What is the difference between ApplicationReadyEvent and ContextRefreshedEvent?
ContextRefreshedEvent fires when the ApplicationContext is refreshed (all beans initialized). ApplicationReadyEvent fires after the context is refreshed AND the application is ready to serve requests (after CommandLineRunner and ApplicationRunner have run). Use ApplicationReadyEvent for post-startup tasks in web applications.
🚨 Common Production Issues
@PostConstruct making blocking network calls that delay startup — run heavy initialization asynchronously or use ApplicationReadyEvent
@PreDestroy not called because JVM killed with SIGKILL instead of SIGTERM — configure Kubernetes terminationGracePeriodSeconds
Circular dependency in BeanPostProcessor — BPPs are special and must not depend on beans they process
Long @PreDestroy blocking graceful shutdown — set spring.lifecycle.timeout-per-shutdown-phase
ApplicationContext refreshed multiple times in tests — use @DirtiesContext carefully
✅ Best Practices
Use @PostConstruct for initialization logic, never in constructors
Keep @PostConstruct fast — slow init delays application startup
Use @PreDestroy to close resources (connections, threads, file handles)
For heavy startup work, use ApplicationReadyEvent so the app starts fast and initializes async
Configure graceful shutdown: server.shutdown=graceful in application.properties
🏛️ Architect's Note
In cloud-native deployments, startup time matters. Kubernetes readiness probes wait for your app to be healthy before routing traffic. If your @PostConstruct methods take 30 seconds loading caches, your pod won't become ready for 30 seconds. Pattern: start fast, serve traffic, warm up asynchronously. Use ApplicationReadyEvent for non-critical initialization and async cache warming. Critical validation (DB connectivity) belongs in @PostConstruct.
💬 Frequently Asked Questions
🎯 Key Takeaways
🔗 Related Topics
🎯 Practice this topic in interviews
↗ Where this topic fits
Spring Boot Technology Guide
Return to the Spring Boot learning hub.
Backend Engineer Career Path
A structured journey through Core Java, Spring Boot, production backend engineering, and interview preparation.
Full Stack Java Developer Career Path
A guided route through frontend foundations, Java backend engineering, delivery workflows, and interview readiness.
Sources
Sources / References
Use these Spring Boot references to verify the concept in official docs and continue into the most relevant SplashRide pages.
Official documentation
Related SplashRide pages
SplashRide Spring Boot learning path
Browse the full Spring Boot topic collection and learning order on SplashRide.
Spring Boot Interview Prep
Practice Spring Boot interview questions and scenario-based answers.
Backend Engineer Career Path
A structured journey through Core Java, Spring Boot, production backend engineering, and interview preparation.
Full Stack Java Developer Career Path
A guided route through frontend foundations, Java backend engineering, delivery workflows, and interview readiness.
IoC Container
Understand the Spring IoC Container — the heart of Spring that manages object creation, dependency wiring, and bean lifecycle in every enterprise application.
Dependency Injection
Master Spring's three DI styles — constructor, setter, and field injection — and understand why constructor injection is the only correct choice for production code.