BeanPostProcessor 原理浅析

缘起

BeanPostProcessor是一个spring的接口. 该接口的作用在于在初始化之前和初始化之后织入自己的逻辑.

分析

BeanPostProcessor接口里面仅有两个方法

1
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

1
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

这两个接口的作用分别是

1
2
3
4
5
postProcessBeforeInitialization方法用于 Apply this BeanPostProcessor to the given new bean instance before any bean initialization callbacks (like InitializingBean's afterPropertiesSet
or a custom init-method, 其实还包括 @PostConstruct). The bean will already be populated with property values.
参数一: bean 就是ioc帮我们创建好的实例,尚未初始化
参数二: beanName 就是bean在ioc容器中的id
此方法返回the bean instance to use, either the original or a wrapped one;

1
postProcessAfterInitialization方法用于 Apply this BeanPostProcessor to the given new bean instance after any bean initialization callbacks (like InitializingBean's afterPropertiesSet or a custom init-method,其实还包括 @PostConstruct). The bean will already be populated with property values.

那么 BeanPostProcessor 什么时候起作用的呢? 在【1】中,我们可以在 MyBeanPostProcessor 的postProcessBeforeInitialization方法第一行打好断点. 然后debug运行App. 则查看如下调用栈

在DefaultSingletonBeanRegistry 的initializeBean方法(其实是DefaultSingletonBeanRegistry 的抽象父类 AbstractAutowireCapableBeanFactory的 initializeBean 方法), 源码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}

if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

​ 源码1

我们可以很清晰的看到一个执行顺序

1
2
3
	applyBeanPostProcessorsBeforeInitialization
--> invokeInitMethods
--> applyBeanPostProcessorsAfterInitialization

applyBeanPostProcessorsBeforeInitialization 的源码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {

Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}

可以看到 applyBeanPostProcessorsBeforeInitialization 方法就是拿出所有的beanPostProcessors进行遍历执行 postProcessBeforeInitialization 方法. 而且我们知道,一旦某个BeanPostProcessor的postProcessBeforeInitialization 方法返回的是null的话, 后续的BeanPostProcessor的postProcessBeforeInitialization 方法是不会执行的.

好,我们回到执行顺序上来,初始化前置处理完毕之后, 我们执行 invokeInitMethods 方法. 该方法中主要执行的就是如果bean实现了InitializingBean接口的话,调用其afterPropertiesSet方法 或者 调用自定义的initedMethod. 源码如下

1
2
3
4
5
6
7
if (mbd != null) {
String initMethodName = mbd.getInitMethodName();
if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}

其中第二行代码, 获取InitMethodName就是获取@Bean注解的initMethod属性的值(具体代码不在这里展开,详见org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(BeanMethod) 中搜索 setInitMethodName)

而且我们发现,initMethod 的执行需要bean不是实现了InitializingBean接口的同时initMethod方法名也是afterPropertiesSet. 这样才能执行initMethod方法. 再回到执行顺序中, 我们invokeInitMethods之后,就会再执行applyBeanPostProcessorsAfterInitialization方法.而这个方法与applyBeanPostProcessorsBeforeInitialization 类似,也是拿出所有的BeanPostProcessors之后遍历执行postProcessAfterInitialization方法. 同applyBeanPostProcessorsBeforeInitialization ,也是如果有一个BeanPostProcessor返回null的话, 则后续BeanPostProcessor就不再执行了.

分析完上述自定义BeanPostProcessor接口之后. 我们还有一个疑问——就是属性的set注入在哪里? 在上图中最后一帧调用栈中. 其源码在AbstractAutowireCapableBeanFactory的doCreateBean方法中

1
2
3
4
5
6
7
8
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}

​ 源码2

其中第六行的initializeBean展开了就是上面说的执行顺序. 而populateBean就是set注入.

最后我们来看看Spring底层常用的BeanPostProcessor.

  1. AsyncAnnotationBeanPostProcessor, 该类的主要目的是用于处理 @Async 注解的类

  2. ApplicationContextAwareProcessor, 该类的目的是能向实现了ApplicationContextAware接口的Bean组件中注入ioc容器. 怎么注入的呢? 该BeanPostProcessor的postProcessAfterInitialization方法是trivial的. 实现功能的是postProcessBeforeInitialization方法. 该方法中调用了 invokeAwareInterfaces方法. 该方法有一段源码如下

    1
    2
    3
    if (bean instanceof ApplicationContextAware) {
    ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
    }

    你看,这样就将ioc容器注入到了bean中去了.

  3. BeanValidationPostProcessor, 该类的目的是对bean进行数据校验. 在Web中用的特别多. 在初始化之前和之后都会去做数据校验. 而校验的逻辑就是调用注入的validator的validate方法进行校验,对于校验出现的异常,拼接成字符串并抛出相应的异常.

  4. InitDestroyAnnotationBeanPostProcessor, 这个类就是用来处理 @PostConstruct 和 @PreDestroy两个注解的. 其中postProcessBeforeInitialization方法处理的是@PostConstruct , postProcessBeforeDestruction方法处理的是@PreDestroy注解. 这就是为什么 InitializeBean的 afterPropertiesSet方法在@PostConstruct注解之后执行(回顾执行顺序,afterPropertiesSet是在invokeInitMethods中,而 @PostConstruct是在applyBeanPostProcessorsBeforeInitialization中.) 同理,这也是为什么DisposableBean的destroy方法在 @PreDestroy 注解之后执行.

  5. AutowiredAnnotationBeanPostProcessor. 这个类就是解释了为什么@Autowired注解可以自动装配. 该类来处理bean被创建完毕之后如何处理被@Autowired注解标注的属性. 因为在上述 AbstractAutowireCapableBeanFactory的doCreateBean方法源码中的populateBean方法里面调用的就是AutowiredAnnotationBeanPostProcessor的postProcessPropertyValues方法, 这个方法有以下源码

    1
    2
    3
    4
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    try {
    metadata.inject(bean, beanName, pvs);
    }

    即没有进到执行顺序中去. 而是在源码2的populateBean阶段就完成了.

DEMO

【1】https://github.com/yfsyfs/backend/tree/master/spring-annotation-lifecycle-beanpostprocessor