Description
I noticed that the behavior of a BeanPostProcessor varies depending on its scope, which is quite confusing:
- Singleton Scope (Default)
- The processor works correctly for all other beans.
- The processor itself does NOT get processed by its own
postProcessBeforeInitialization / postProcessAfterInitialization methods.
This happens because the BeanPostProcessor bean is instantiated early during BeanPostProcessor registration, then stored in the singleton pool.
Later, when other non-lazy-init singleton beans are created, since this processor already exists in the singleton pool, its lifecycle is not re-executed, so it does not process itself.
- Prototype Scope (
@Scope("prototype"))
- The processor works correctly for all other beans (including beans created after the processor is instantiated).
- The processor itself DOES get processed by its own
postProcessBeforeInitialization / postProcessAfterInitialization methods.
This happens because the prototype-scoped BeanPostProcessor is not cached in the singleton pool. Every time it is created, it goes through the full bean lifecycle, which causes the BeanPostProcessor to apply its own post-processing to itself.
This leads to inconsistent behavior: the same BeanPostProcessor exhibits different lifecycle callback behavior based on its scope.
This inconsistency is not mentioned in the official documentation, which can lead to unexpected and confusing results for developers.
Steps to Reproduce
- Define a class
UserBeanPostProcessor that implements BeanPostProcessor and logs in both callback methods.
- Mark it with
@Component (default singleton scope).
- Run the application: logs show the processor works for other beans, but no logs for itself.
- Add
@Scope("prototype") to the processor.
- Run the application: logs show the processor works for other beans and processes itself.
Expected Behavior
The behavior should be consistent across both scopes:
- Either the processor never processes itself (in both singleton and prototype), or
- The processor always processes itself consistently, with clear documentation about the recursion risks.
Description
I noticed that the behavior of a
BeanPostProcessorvaries depending on its scope, which is quite confusing:postProcessBeforeInitialization/postProcessAfterInitializationmethods.This happens because the
BeanPostProcessorbean is instantiated early duringBeanPostProcessorregistration, then stored in the singleton pool.Later, when other non-lazy-init singleton beans are created, since this processor already exists in the singleton pool, its lifecycle is not re-executed, so it does not process itself.
@Scope("prototype"))postProcessBeforeInitialization/postProcessAfterInitializationmethods.This happens because the prototype-scoped
BeanPostProcessoris not cached in the singleton pool. Every time it is created, it goes through the full bean lifecycle, which causes theBeanPostProcessorto apply its own post-processing to itself.This leads to inconsistent behavior: the same
BeanPostProcessorexhibits different lifecycle callback behavior based on its scope.This inconsistency is not mentioned in the official documentation, which can lead to unexpected and confusing results for developers.
Steps to Reproduce
UserBeanPostProcessorthat implementsBeanPostProcessorand logs in both callback methods.@Component(default singleton scope).@Scope("prototype")to the processor.Expected Behavior
The behavior should be consistent across both scopes: