Bean Lifecycle
From BeanDefinition to destruction — Aware interfaces, BeanPostProcessor, @PostConstruct, InitializingBean, init/destroy methods, @PreDestroy, bean scopes and BeanFactoryPostProcessor.
#Introduction
One of the most important Spring interview topics. Almost every senior-level interviewer asks some variation of: Explain the Spring bean lifecycle. When is @PostConstruct called? When is @PreDestroy called? What's the difference between BeanFactoryPostProcessor and BeanPostProcessor? What are bean scopes? What is a singleton bean? How are prototype beans destroyed? What happens internally when Spring starts?
Understanding the bean lifecycle explains how Spring creates, initializes, manages, proxies and destroys every bean.
#What is a Spring Bean?
A bean is simply an object that is created by Spring, managed by Spring and stored inside the IoC container.
@Service
public class UserService {
}#Complete Bean Lifecycle
#Step 1 — BeanDefinition Creation
Spring scans your project for @Component, @Service, @Repository, @Controller and @Configuration classes. Each discovered bean becomes a BeanDefinition, which stores metadata such as the bean class, name, scope, lazy/eager initialization, constructor information and lifecycle callbacks. No object has been created yet.
#Step 2 — Bean Instantiation
Spring creates the object — internally like UserService service = new UserService();. The object exists, but dependencies aren't injected yet (except constructor arguments).
#Step 3 — Dependency Injection
@Autowired
private UserRepository repository;#Step 4 — Aware Interfaces
If a bean implements an Aware interface, Spring injects framework objects:
public class UserService implements BeanNameAware {
@Override
public void setBeanName(String name) {
System.out.println(name);
}
}Common Aware interfaces: BeanNameAware, BeanFactoryAware, ApplicationContextAware, EnvironmentAware and ResourceLoaderAware. These are mainly used by framework developers and advanced infrastructure components.
#Step 5 — BeanPostProcessor (Before Initialization)
Spring calls postProcessBeforeInitialization():
@Component
public class MyProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
}This runs before the bean's init callbacks.
#Step 6 — @PostConstruct
One of the most asked interview questions.
@Service
public class UserService {
@PostConstruct
public void init() {
System.out.println("Bean Initialized");
}
}Called once, after bean creation and dependency injection. Perfect for loading caches, reading configuration, opening connections (if appropriate) and initializing in-memory data.
#Step 7 — InitializingBean
public class UserService implements InitializingBean {
@Override
public void afterPropertiesSet() {
}
}afterPropertiesSet() runs after @PostConstruct. Today @PostConstruct is generally preferred because it avoids coupling your class to Spring interfaces.
#Step 8 — Custom initMethod
@Bean(initMethod = "initialize")
public UserService service() {
return new UserService();
}
public void initialize() {
}Spring calls it after afterPropertiesSet().
Initialization Order
Interview favourite:
#Step 9 — BeanPostProcessor (After Initialization)
Spring executes postProcessAfterInitialization(). This is where many Spring features create proxies — Spring AOP, @Transactional, Spring Security, @Async and @Cacheable.
Why BeanPostProcessor Matters
@Transactional
public void save() {
}Without BeanPostProcessor, features like @Transactional and @Async wouldn't work.
#Step 10 — Bean Ready
The bean is fully initialized and lives in the ApplicationContext, available to controllers, services and repositories.
#Step 11 — @PreDestroy
When the application stops:
@Service
public class UserService {
@PreDestroy
public void destroy() {
System.out.println("Cleaning Resources");
}
}Called before bean destruction. Useful for closing resources, releasing locks, flushing buffers and stopping background tasks.
#Step 12 — DisposableBean
public class UserService implements DisposableBean {
@Override
public void destroy() {
}
}Again, @PreDestroy is generally preferred because it avoids Spring-specific coupling.
#Step 13 — Custom destroyMethod
@Bean(destroyMethod = "cleanup")
public UserService service() {
return new UserService();
}Spring executes cleanup() during shutdown.
Destruction Order
#Bean Scopes
Interview favourite.
Singleton (Default)
@Service
public class UserService {
}One bean for the entire ApplicationContext, shared everywhere. The default scope.
Prototype
@Scope("prototype")
@Component
public class Report {
}Every request for the bean creates a new instance.
Request Scope
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)One bean per HTTP request. Only available in web applications. (@RequestScope is a shortcut that includes the proxy.)
Session Scope
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)One bean per HTTP session. Useful for user-specific state. (@SessionScope is the shortcut.)
Application Scope
@Scope(value = "application")One bean for the entire web application (ServletContext).
Scope Comparison
| Scope | Instances |
|---|---|
| Singleton | One per ApplicationContext |
| Prototype | New instance per lookup |
| Request | One per HTTP request |
| Session | One per HTTP session |
| Application | One per web application |
#BeanFactoryPostProcessor vs BeanPostProcessor
A very important interview topic.
BeanFactoryPostProcessor works on BeanDefinitions, before beans are created — e.g. modifying bean definitions, changing bean properties, registering additional bean definitions (PropertySourcesPlaceholderConfigurer resolves ${...} placeholders this way).
BeanPostProcessor works on actual bean instances:
…e.g. AOP proxies, transaction proxies, security proxies and logging wrappers.
| BeanFactoryPostProcessor | BeanPostProcessor |
|---|---|
Works on BeanDefinition | Works on the bean instance |
| Before instantiation | After instantiation (around initialization) |
| Metadata | Object |
| Runs earlier | Runs later |
This comparison is frequently asked.
#Complete Internal Flow
#Common Mistakes
Heavy Work in the Constructor
// ❌ At construction time, field/setter dependencies aren't available yet
public UserService() {
loadLargeCache();
}
// ✅ Better
@PostConstruct
public void init() {
loadLargeCache();
}Forgetting the Prototype Lifecycle
Developers often assume @PreDestroy runs for prototype beans. It doesn't — the application is responsible for cleaning them up if necessary.
Using BeanPostProcessor for Business Logic
BeanPostProcessor is for framework-level customization. Don't implement business rules there.
Depending on Bean Initialization Order
Don't assume one bean initializes before another unless you define that relationship explicitly (through dependency injection, or @DependsOn where appropriate).
#Interview Questions
Q1What is the Spring bean lifecycle?
Bean definition → instantiation → dependency injection → Aware interfaces → BeanPostProcessor (before) → @PostConstruct → afterPropertiesSet() → initMethod() → BeanPostProcessor (after) → bean ready → @PreDestroy → destroy() → destroyMethod().
Q2When is @PostConstruct executed?
After dependency injection is complete and before the bean is made available for use.
Q3When is @PreDestroy executed?
Just before a managed bean is destroyed during application shutdown.
Q4What is the difference between BeanPostProcessor and BeanFactoryPostProcessor?
| BeanFactoryPostProcessor | BeanPostProcessor |
|---|---|
Operates on BeanDefinition metadata | Operates on bean instances |
| Before bean creation | Before and after bean initialization |
Q5Which scope is the default?
singleton.
Q6Does Spring destroy prototype beans?
No. Spring creates them but does not invoke destruction callbacks automatically.
Q7Which interface provides the afterPropertiesSet() callback?
InitializingBean.
Q8Which interface provides the destroy() callback?
DisposableBean.
Q9Why is BeanPostProcessor important?
It enables framework features such as proxy creation for @Transactional, @Async, caching and AOP.
Q10What is the initialization order?
Constructor → dependency injection → Aware methods → BeanPostProcessor (before) → @PostConstruct → afterPropertiesSet() → initMethod() → BeanPostProcessor (after).
#Key Takeaways
- A Spring bean goes through a well-defined lifecycle from creation to destruction.
@PostConstructis ideal for initialization after dependency injection.@PreDestroyreleases resources during shutdown.BeanFactoryPostProcessormodifies metadata before instantiation;BeanPostProcessorcustomizes instances around initialization.singletonis the default scope; prototype beans aren't destroyed by Spring.- Transactions, AOP, security, async execution and caching rely on
BeanPostProcessorand proxies.