Understanding @PostConstruct in Spring: Specs, Lifecycle, and Alternatives
This article explains the JSR‑250 @PostConstruct annotation, its specifications, how Spring implements its lifecycle handling, execution timing, practical code examples, the deprecation in Java 9+, and alternative approaches such as InitializingBean and DisposableBean.
Spring’s @PostConstruct and @PreDestroy annotations let developers run custom logic during bean initialization and destruction, but they are defined by the JSR‑250 specification, not by Spring itself.
JSR‑250 Specification
JSR‑250 defines a set of annotations in javax.annotation (e.g., @Resource, @PostConstruct, @PreDestroy) that describe how resources should be managed. The spec provides only the contract; concrete frameworks like Spring implement the behavior.
@PostConstruct Convention
According to JSR‑250, a method annotated with @PostConstruct must:
Have no parameters (unless used as an EJB interceptor).
Return void.
Not throw checked exceptions.
Be any visibility (public, protected, package‑private, or private).
Not be static (except for client applications).
May be final.
If it throws an unchecked exception, the bean must not be placed in service unless the exception can be handled and the bean can recover.
Execution Timing in Spring
When Spring creates a bean, it invokes methods annotated with @PostConstruct after the constructor finishes and before any init() method. The method runs once per bean instance during container startup.
Example Demonstration
In a Spring Boot project (Java 8), the following service shows the lifecycle callbacks:
@Service
public class OrderService {
public OrderService(){
System.out.println("OrderService constructor executed...");
}
@PostConstruct
private void init() {
System.out.println("PostConstruct method called");
}
@PreDestroy
private void shutdown() {
System.out.println("PreDestroy method called");
}
}Running the application prints:
OrderService constructor executed...
PostConstruct method calledWhen the application stops, the @PreDestroy method logs:
PreDestroy method calledRemoval in Java 9+ and Workarounds
Starting with Java 9, @PostConstruct and @PreDestroy are deprecated and slated for removal in Java 11. Two common solutions are:
Add the legacy dependency manually:
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>Replace the annotations with Spring’s own lifecycle interfaces InitializingBean and DisposableBean:
@Service
public class PaymentService implements InitializingBean, DisposableBean {
public PaymentService(){
System.out.println("PaymentService constructor executed...");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet method called");
}
@Override
public void destroy() throws Exception {
System.out.println("destroy method called");
}
}Running this bean logs the constructor, then afterPropertiesSet, and on shutdown logs destroy.
Spring Implementation Details
Spring processes @PostConstruct via the BeanPostProcessor extension point. The concrete class CommonAnnotationBeanPostProcessor (subclass of InitDestroyAnnotationBeanPostProcessor) scans beans for the annotations and invokes the corresponding methods via reflection.
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}The processing flow is roughly:
--> Spring IOC container instantiates bean
--> Calls BeanPostProcessor.postProcessBeforeInitialization()
--> Invokes bean's @PostConstruct method(s)
--> Calls bean's init methods (e.g., afterPropertiesSet)
--> Calls BeanPostProcessor.postProcessAfterInitialization()Inside InitDestroyAnnotationBeanPostProcessor, the method postProcessBeforeInitialization() builds lifecycle metadata, finds @PostConstruct methods, and invokes them.
InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization()
-> findLifecycleMetadata()
-> buildLifecycleMetadata()
-> locate @PostConstruct methods
-> locate @PreDestroy methods
-> metadata.invokeInitMethods(bean, beanName);Conclusion
Key takeaways: Spring merely implements the JSR‑250 contract for @PostConstruct; the annotation is deprecated from Java 9 onward, so adding the legacy dependency or switching to InitializingBean / DisposableBean is recommended for future‑proof code.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Senior Brother's Insights
A public account focused on workplace, career growth, team management, and self-improvement. The author is the writer of books including 'SpringBoot Technology Insider' and 'Drools 8 Rule Engine: Core Technology and Practice'.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
