What is a BeanPostProcessor? When does it run? Real-world… — Cracked Java
// Spring Framework & Spring Boot · Bean Scopes & Lifecycle
SeniorTheoryBig Tech

What is a BeanPostProcessor? When does it run? Real-world example.

A BeanPostProcessor (BPP) is a container extension point that lets you intercept every bean instance right around its initialization callbacks — and it's the machinery behind @Autowired, @Transactional, and AOP. If you understand BPP, you understand how "magic" annotations actually work.

The interface

Two callbacks, both invoked by the container for each bean:

public interface BeanPostProcessor {
    default Object postProcessBeforeInitialization(Object bean, String name) { return bean; }
    default Object postProcessAfterInitialization(Object bean, String name)  { return bean; }
}

The key superpower: each method returns an object, and the container uses the returned reference going forward. So a BPP can replace a bean with a proxy that wraps it. That return-and-replace is exactly how Spring creates transactional and AOP proxies.

When it runs

Per bean, after instantiation and property population:

  • postProcessBeforeInitialization runs before @PostConstruct / afterPropertiesSet() / init-method.
  • postProcessAfterInitialization runs after all init callbacks — this is where AOP/transaction proxies are typically created and returned.

It operates on fully instantiated instances, which is the defining contrast with BeanFactoryPostProcessor (which works on bean definitions before any instance exists).

Real-world examples (Spring's own)

These aren't toy examples — they're how core features are implemented:

  • AutowiredAnnotationBeanPostProcessor — implements @Autowired and @Value injection.
  • CommonAnnotationBeanPostProcessor — implements @PostConstruct, @PreDestroy, @Resource.
  • AnnotationAwareAspectJAutoProxyCreator — wraps beans in AOP/@Transactional proxies.
@Component
public class TimingBpp implements BeanPostProcessor {
    public Object postProcessAfterInitialization(Object bean, String name) {
        if (bean instanceof ExpensiveService) {
            return Proxy.newProxyInstance(/* ...wrap with timing... */);
        }
        return bean;   // pass others through untouched
    }
}

Mark your status