mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Document registration recommendations for BeanPostProcessor and BeanFactoryPostProcessor
Closes gh-34964
This commit is contained in:
@@ -67,6 +67,13 @@ interface, clearly indicating the post-processor nature of that bean. Otherwise,
|
||||
Since a `BeanPostProcessor` needs to be instantiated early in order to apply to the
|
||||
initialization of other beans in the context, this early type detection is critical.
|
||||
|
||||
Furthermore, when registering a `BeanPostProcessor` via an `@Bean` factory method,
|
||||
declare the method as `static` and ideally with no dependencies. Doing so avoids eager
|
||||
initialization of the configuration class and other beans, which would make them
|
||||
ineligible for full post-processing (such as auto-proxying). See the
|
||||
"BeanPostProcessor-returning `@Bean` methods" section in the
|
||||
{spring-framework-api}/context/annotation/Bean.html[`@Bean`] javadoc for details.
|
||||
|
||||
[[beans-factory-programmatically-registering-beanpostprocessors]]
|
||||
.Programmatically registering `BeanPostProcessor` instances
|
||||
NOTE: While the recommended approach for `BeanPostProcessor` registration is through
|
||||
@@ -80,7 +87,7 @@ of execution. Note also that `BeanPostProcessor` instances registered programmat
|
||||
are always processed before those registered through auto-detection, regardless of any
|
||||
explicit ordering.
|
||||
|
||||
.`BeanPostProcessor` instances and AOP auto-proxying
|
||||
.`BeanPostProcessor` instances and early initialization
|
||||
[NOTE]
|
||||
====
|
||||
Classes that implement the `BeanPostProcessor` interface are special and are treated
|
||||
@@ -90,17 +97,23 @@ of the `ApplicationContext`. Next, all `BeanPostProcessor` instances are registe
|
||||
in a sorted fashion and applied to all further beans in the container. Because AOP
|
||||
auto-proxying is implemented as a `BeanPostProcessor` itself, neither `BeanPostProcessor`
|
||||
instances nor the beans they directly reference are eligible for auto-proxying and,
|
||||
thus, do not have aspects woven into them.
|
||||
thus, do not have aspects woven into them. More generally, any bean that is instantiated
|
||||
during this early phase is not eligible for full post-processing by all
|
||||
`BeanPostProcessor` instances.
|
||||
|
||||
For any such bean, you should see an informational log message: `Bean someBean is not
|
||||
eligible for getting processed by all BeanPostProcessor interfaces (for example: not
|
||||
eligible for auto-proxying)`.
|
||||
For any such bean, you should see a WARN-level log message similar to the following.
|
||||
|
||||
If you have beans wired into your `BeanPostProcessor` by using autowiring or
|
||||
`@Resource` (which may fall back to autowiring), Spring might access unexpected beans
|
||||
when searching for type-matching dependency candidates and, therefore, make them
|
||||
ineligible for auto-proxying or other kinds of bean post-processing. For example, if you
|
||||
have a dependency annotated with `@Resource` where the field or setter name does not
|
||||
[quote]
|
||||
Bean 'someBean' of type [org.example.SomeType] is not eligible for getting processed by
|
||||
all BeanPostProcessors (for example: not eligible for auto-proxying).
|
||||
|
||||
To minimize the number of beans affected, register a `BeanPostProcessor` with a
|
||||
`static` `@Bean` method that has no dependencies (see the note above). If you have
|
||||
beans wired into your `BeanPostProcessor` by using autowiring or `@Resource` (which
|
||||
may fall back to autowiring), Spring might access unexpected beans when searching
|
||||
for type-matching dependency candidates and, therefore, make them ineligible for
|
||||
auto-proxying or other kinds of bean post-processing. For example, if you have a
|
||||
dependency annotated with `@Resource` where the field or setter name does not
|
||||
directly correspond to the declared name of a bean and no name attribute is used,
|
||||
Spring accesses other beans for matching them by type.
|
||||
====
|
||||
@@ -164,7 +177,48 @@ Kotlin::
|
||||
----
|
||||
======
|
||||
|
||||
The following `beans` element uses the `InstantiationTracingBeanPostProcessor`:
|
||||
You can register the `InstantiationTracingBeanPostProcessor` with Java configuration
|
||||
by using a `static` `@Bean` method (recommended to avoid eager initialization of the
|
||||
configuration class and other beans):
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
@Configuration
|
||||
public class AppConfig {
|
||||
|
||||
@Bean
|
||||
public static InstantiationTracingBeanPostProcessor instantiationTracingBeanPostProcessor() {
|
||||
return new InstantiationTracingBeanPostProcessor();
|
||||
}
|
||||
|
||||
// ... other bean definitions
|
||||
}
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
|
||||
----
|
||||
@Configuration
|
||||
class AppConfig {
|
||||
|
||||
@Bean
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun instantiationTracingBeanPostProcessor() = InstantiationTracingBeanPostProcessor()
|
||||
}
|
||||
|
||||
// ... other bean definitions
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
Alternatively, the `InstantiationTracingBeanPostProcessor` can be registered via the
|
||||
`bean` element with XML configuration:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@@ -300,6 +354,23 @@ implement the `BeanFactoryPostProcessor` interface. It uses these beans as bean
|
||||
post-processors, at the appropriate time. You can deploy these post-processor beans as
|
||||
you would any other bean.
|
||||
|
||||
When registering a `BeanFactoryPostProcessor` via an `@Bean` factory method in a
|
||||
`@Configuration` class, declare the method as `static` to avoid lifecycle conflicts
|
||||
with annotation processing (such as `@Autowired`, `@Value`, and `@PostConstruct`) in the
|
||||
configuration class. See the "BeanFactoryPostProcessor-returning `@Bean` methods"
|
||||
section in the {spring-framework-api}/context/annotation/Bean.html[`@Bean`] javadoc
|
||||
for details and an example.
|
||||
|
||||
For any non-static `@Bean` factory method with a `BeanFactoryPostProcessor` return type,
|
||||
you should see an INFO-level log message similar to the following.
|
||||
|
||||
[quote]
|
||||
@Bean method MyConfig.myBfpp is non-static and returns an object assignable to Spring's
|
||||
BeanFactoryPostProcessor interface. This will result in a failure to process annotations
|
||||
such as @Autowired, @Resource, and @PostConstruct within the method's declaring
|
||||
@Configuration class. Add the 'static' modifier to this method to avoid these container
|
||||
lifecycle issues; see @Bean javadoc for complete details.
|
||||
|
||||
NOTE: As with ``BeanPostProcessor``s , you typically do not want to configure
|
||||
``BeanFactoryPostProcessor``s for lazy initialization. If no other bean references a
|
||||
`Bean(Factory)PostProcessor`, that post-processor will not get instantiated at all.
|
||||
|
||||
+7
@@ -40,6 +40,13 @@ import org.springframework.beans.BeansException;
|
||||
* A {@code BeanFactoryPostProcessor} may also be registered programmatically
|
||||
* with a {@code ConfigurableApplicationContext}.
|
||||
*
|
||||
* <p>When registering a {@code BeanFactoryPostProcessor} via an {@code @Bean} method
|
||||
* in a {@code @Configuration} class, use a {@code static} method to avoid eager
|
||||
* initialization of other beans in the configuration class. See the
|
||||
* "BeanFactoryPostProcessor-returning {@code @Bean} methods" section in
|
||||
* {@link org.springframework.context.annotation.Bean @Bean}'s javadoc for details
|
||||
* and an example.
|
||||
*
|
||||
* <h3>Ordering</h3>
|
||||
* <p>{@code BeanFactoryPostProcessor} beans that are autodetected in an
|
||||
* {@code ApplicationContext} will be ordered according to
|
||||
|
||||
+8
@@ -35,6 +35,14 @@ import org.springframework.beans.BeansException;
|
||||
* created. A plain {@code BeanFactory} allows for programmatic registration of
|
||||
* post-processors, applying them to all beans created through the bean factory.
|
||||
*
|
||||
* <p>When registering a {@code BeanPostProcessor} via an {@code @Bean} method in
|
||||
* a {@code @Configuration} class, use a {@code static} method with ideally no
|
||||
* dependencies in order to avoid eager initialization that can make other beans
|
||||
* ineligible for full post-processing. See the "BeanPostProcessor-returning
|
||||
* {@code @Bean} methods" section in
|
||||
* {@link org.springframework.context.annotation.Bean @Bean}'s javadoc for details
|
||||
* and an example.
|
||||
*
|
||||
* <h3>Ordering</h3>
|
||||
* <p>{@code BeanPostProcessor} beans that are autodetected in an
|
||||
* {@code ApplicationContext} will be ordered according to
|
||||
|
||||
@@ -194,6 +194,31 @@ import org.springframework.core.annotation.AliasFor;
|
||||
* issued for any non-static {@code @Bean} methods having a return type assignable to
|
||||
* {@code BeanFactoryPostProcessor}.
|
||||
*
|
||||
* <h3>{@code BeanPostProcessor}-returning {@code @Bean} methods</h3>
|
||||
*
|
||||
* <p>Similarly, special consideration must be taken for {@code @Bean} methods that return Spring
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor BeanPostProcessor}
|
||||
* ({@code BPP}) types. Because {@code BPP} objects must be instantiated early in the container
|
||||
* lifecycle, a non-static {@code @Bean} method that returns a {@code BPP} will cause eager
|
||||
* initialization of its declaring {@code @Configuration} class, which can make other beans in the
|
||||
* {@code @Configuration} class (as well as depencencies of those beans) ineligible for full
|
||||
* post-processing. To avoid these lifecycle issues, mark {@code BPP}-returning {@code @Bean}
|
||||
* methods as {@code static}. For example:
|
||||
*
|
||||
* <pre class="code">
|
||||
* @Bean
|
||||
* public static MyBeanPostProcessor myBeanPostProcessor() {
|
||||
* return new MyBeanPostProcessor();
|
||||
* }</pre>
|
||||
*
|
||||
* By marking this method as {@code static}, it can be invoked without causing instantiation of its
|
||||
* declaring {@code @Configuration} class. Furthermore, the method should ideally not declare any
|
||||
* dependencies so that the container does not need to instantiate other beans to create the
|
||||
* post-processor, which would make those beans ineligible for post-processing as well. For any such
|
||||
* bean, you should see a WARN-level log message similar to the following: "Bean 'someBean' of type
|
||||
* [org.example.SomeType] is not eligible for getting processed by all BeanPostProcessors (for example:
|
||||
* not eligible for auto-proxying)".
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Costin Leau
|
||||
* @author Chris Beams
|
||||
|
||||
Reference in New Issue
Block a user