自定义BeanFactoryPostProcessor的错误做法

BeanFactoryPostProcessor 介绍

Spring提供了很多个扩展点,包括BeanFactoryPostProcessor、BeanPostProcessor、Aware,今天主要讲述下 BeanFactoryPostProcessor 的功能及错误用法。

BeanFactoryPostProcessor 能做什么?先贴下源代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package org.springframework.beans.factory.config;

import org.springframework.beans.BeansException;

/**
* Factory hook that allows for custom modification of an application context's
* bean definitions, adapting the bean property values of the context's underlying
* bean factory.
*
* <p>Useful for custom config files targeted at system administrators that
* override bean properties configured in the application context. See
* {@link PropertyResourceConfigurer} and its concrete implementations for
* out-of-the-box solutions that address such configuration needs.
*
* <p>A {@code BeanFactoryPostProcessor} may interact with and modify bean
* definitions, but never bean instances. Doing so may cause premature bean
* instantiation, violating the container and causing unintended side-effects.
* If bean instance interaction is required, consider implementing
* {@link BeanPostProcessor} instead.
*
* <h3>Registration</h3>
* <p>An {@code ApplicationContext} auto-detects {@code BeanFactoryPostProcessor}
* beans in its bean definitions and applies them before any other beans get created.
* A {@code BeanFactoryPostProcessor} may also be registered programmatically
* with a {@code ConfigurableApplicationContext}.
*
* <h3>Ordering</h3>
* <p>{@code BeanFactoryPostProcessor} beans that are autodetected in an
* {@code ApplicationContext} will be ordered according to
* {@link org.springframework.core.PriorityOrdered} and
* {@link org.springframework.core.Ordered} semantics. In contrast,
* {@code BeanFactoryPostProcessor} beans that are registered programmatically
* with a {@code ConfigurableApplicationContext} will be applied in the order of
* registration; any ordering semantics expressed through implementing the
* {@code PriorityOrdered} or {@code Ordered} interface will be ignored for
* programmatically registered post-processors. Furthermore, the
* {@link org.springframework.core.annotation.Order @Order} annotation is not
* taken into account for {@code BeanFactoryPostProcessor} beans.
*
* @author Juergen Hoeller
* @author Sam Brannen
* @since 06.07.2003
* @see BeanPostProcessor
* @see PropertyResourceConfigurer
*/
@FunctionalInterface
public interface BeanFactoryPostProcessor {

/**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for overriding or adding
* properties even to eager-initializing beans.
* @param beanFactory the bean factory used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

比较重要的内容是两段话是:

  • 这是 BeanFactory 钩子,允许对应用程序上下文的bean定义进行自定义修改,从而调整上下文底层bean工厂的bean属性值。
  • 可以与bean定义交互并修改bean定义,但决不能与bean实例交互。这样做可能会导致意外的副作用。如果需要和bean实例交互,请考虑实现 BeanPostProcessor。

下面那段话的意思是说,你可以hack修改bean的定义,但你不能在这个地方触发 bean 的实例化,否则可能会有无法意料的作用。所以,绝对不允许在 BeanFactoryPostProcessor 中触发 bean 的实例化。在这个阶段, bean 还没有实例化,之后会根据 bean 的定义来实例化,在这阶段你添加不了新的 bean 定义,但可以修改 bean 的定义,不能提前实例化 bean,也因为可能还要其他 BeanFactoryPostProcessor 需要修改这个bean 的定义。

一种提前实例化导致的错误

在实例化 bean 的时候,会为每个 bean 调用每一个的 BeanPostProcessor 实现类。在spring 的启动流程中,是先实例化并执行所有的 BeanFactoryPostProcessor, 然后再向容器中注册 BeanPostProcessor。 假如我在 BeanFactoryPostProcessor 实例化了 bean,会导致此时有一些 BeanPostProcessor 还未注册,所以一些 BeanPostProcessor 将无法执行到,比如 CommonAnnotationBeanPostProcessor,这个处理器用于处理 @PostConstruct 注解,用来初始化 bean,如果你在 BeanFactoryPostProcessor 中一不小心实例化了这个bean,那么 @PostConstruct 修饰的方法将不会执行。

同理,@Autowired 等注解也将失效。

参考: https://www.jianshu.com/p/3d099ea43b0e