Spring bean lifecycle and proxies
- Last updated
- Prerequisites:
- Spring Boot basics
- Understanding of dependency injection and annotations
- spring
- springboot
- ioc
- proxy
- aop
- bean-lifecycle
Read at your depth
The practical view
Spring creates beans via the ApplicationContext: @Component/@Service/@Repository classes are instantiated, dependencies injected, then post-processed. The bean lifecycle is: instantiation → populate properties → @PostConstruct / InitializingBean.afterPropertiesSet → proxy wrapping (if needed) → ready. @PreDestroy / DisposableBean.destroy runs on shutdown. AOP advice (@Transactional, @Secured, @Async, custom @Aspect) is applied by wrapping the bean in a proxy: Spring creates either a JDK dynamic proxy (interface-based) or a CGLIB subclass proxy (class-based). Method calls on the injected reference go through the proxy, which applies the advice, then delegates to the real bean.
Legacy vs modern
Transaction via self-invocation vs via the proxied reference
Calling a @Transactional method through this bypasses the proxy and silently loses the transaction; going through the injected proxy applies the advice.
@Service
class OrderService {
public void place(Order o) {
saveAndCharge(o); // this.saveAndCharge → raw bean, no proxy
}
@Transactional
void saveAndCharge(Order o) { ... }
}@Service
class OrderService {
public void place(Order o) {
self().saveAndCharge(o); // through the proxy
}
@Transactional
void saveAndCharge(Order o) { ... }
}Interview gotchas
Context
This is the classic Spring proxy question — the interviewer wants the mechanism (proxy wrapping, self-invocation bypass), not just 'it doesn't work'.
The mechanical answer
Spring wraps the bean in a proxy whose interceptor chain contains the transaction advisor. Any external caller holds the proxy, so calls flow through TransactionInterceptor, which begins/commits/rolls back. A call to this.method() resolves against the raw target instance — this is never the proxy — so the invocation never enters the interceptor chain and no transaction is created. The failure is silent because the method body still runs (the missing piece is the boundary). Fixes: self-injection of the proxy, moving the method to a collaborating bean, or using TransactionTemplate (programmatic, no proxy needed).
Trap
The naive answer is 'make the method public' — visibility is not the cause; proxy interceptor chains apply to public methods but the bypass is about the invocation target, not visibility. Another trap: claiming the transaction rolls back on checked exceptions by default — default rollback is only on RuntimeException/Error, which is a separate classic gotcha candidates should name. Combining both shows real Spring experience.
Context
The interviewer wants to verify knowledge of the two proxy strategies and their constraints — a common senior-adjacent question.
The mechanical answer
JDK dynamic proxies use Proxy.newProxyInstance to create a class implementing the bean's interfaces; the InvocationHandler routes calls through the advisor chain. They require the target to have at least one interface and cannot intercept non-interface (concrete-class) methods. CGLIB subclasses the target class at runtime, overriding non-final, non-private methods, so it works for concrete classes. Since Spring Boot 2.x defaults proxyTargetClass=true, CGLIB is the default even when interfaces exist. CGLIB constraints: final classes and final methods cannot be proxied, constructors run twice (proxy + target instantiation), and the proxy calls the target's constructor, which matters for expensive construction or self-initialization in the constructor.
Trap
The trap answer is 'Spring always uses CGLIB'. Pre-Boot-2.0 the default was JDK proxies when interfaces were present; Boot 2.x flipped the default. Another trap: claiming CGLIB proxies intercept private methods — they cannot (they subclass). Candidates who mention that self-invocation and final methods are both 'bypass the proxy' scenarios, and that constructor-based self-init bypasses post-processing, demonstrate deep understanding.