The full picture
| BeanFactoryPostProcessor | BeanPostProcessor | |
|---|---|---|
| Runs | Once, at startup | Around every bean's initialization |
| Operates on | BeanDefinitions (metadata) | Bean instances |
| Can | Change class, scope, properties; add definitions (BDRPP) | Mutate the bean, or REPLACE it (proxy) |
| Powers | ${…} placeholders, @Configuration parsing, @ConfigurationProperties scanning | @Autowired, @PostConstruct, @Transactional/@Async proxies, @Validated |
@Component
class TimedAnnotationProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String name) {
if (!hasTimedMethods(bean.getClass())) return bean;
return Proxy.newProxyInstance( // return value REPLACES the bean
bean.getClass().getClassLoader(),
bean.getClass().getInterfaces(),
(proxy, method, args) -> {
long t0 = System.nanoTime();
try { return method.invoke(bean, args); }
finally { metrics.record(name, method, System.nanoTime() - t0); }
});
}
}