Skip to main content

Spring BeanPostProcessor执行顺序问题

Spring Framework版本:5.3.x

BeanPostProcessor 在Spring框架中举足轻重,还有很多继承的类。

作用:管理Bean的生命周期:Bean实例化--->Bean初始化--->Bean使用中--->Bean销毁

在Spring 容器初始化的时候就会存在这些类执行的一个先后的问题,今天我们就把这些类的执行先后顺序进行梳理。

1. BeanPostProcessor的分类

BeanPostProcessor 作为顶层接口会有很多的继承接口和实现类,下图就是分类:

BeanPostProcessor分门别类

如上图所示包括 BeanPostProcessor 在内,一共有五个接口类。分成了三个功能模块。

  • Bean实例化这要由InstantiationAwareBeanPostProcessor、SmartInstantiationAwareBeanPostProcessor负责。
  • Bean初始化由BeanPostProcessor、MergedBeanDefinitionPostProcessor两个接口负责
  • Bean销毁由DestructionAwareBeanPostProcessor接口负责

从分类可以看出来这个五个接口分别对应Bean的三个阶段:实例化、初始化、以及销毁。那么各个阶段里面的执行顺序是怎么样的我们接着往下分析

2. 接口的执行顺序

BeanPostProcessor主要负责Bean的生命周期,那么我们从获取Bean的接口入手看获取到Bean的过程中需要执行那些接口。跟踪代码最终跟踪到了 AbstractBeanFactory#doGetBean方法:

//AbstractBeanFactory#doGetBean
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

在这个当中有一个 createBean 方法。从名称可以知道是用来创建Bean的(实例化)。在这个方法里面主要有三段重要代码:

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {

//省略部分代码

// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}


// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}

// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}

return exposedObject;
}

这段代码涵盖了上面五个接口的四个分别是:InstantiationAwareBeanPostProcessor、SmartInstantiationAwareBeanPostProcessor、BeanPostProcessor、MergedBeanDefinitionPostProcessor。唯一的Bean的销毁,Bean的销毁是随着Spring容器销毁而销毁的。整个执行的流程和步骤如下图:

BeanPostProcessor执行顺序

从上图的执行顺序可以看出来:

  • 接口之间的执行顺序不是严格按照: 实例化->初始化->销毁 这样的严格顺序来进行。接口方法之间的顺序会有穿插的情况。
  • InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 方法执行如果返回了对应的Bean的实例,后续的接口都不会执行了。 这里我们可以加入自定义的类。典型的例子就是动态代理的实现,可以继承当前接口并且在改方法中实现动态代理。这样在Spring 容器中的实例就是一个动态代理实例。
  • DestructionAwareBeanPostProcessor 接口一般情况下是不会执行,只有当Spring容器销毁就会触发容器里面类的销毁机制。
  • 同一种类型接口如果有继承 PriorityOrdered 和Ordered进行排序。

Tips: 对于基于BeanPostProcessor自定义开发来说,主要用于自定义方法或者属性类上面的注解。这里举两个Spring的例子:AutowiredAnnotationBeanPostProcessor 处理@Autowired, @Value注解, AsyncAnnotationBeanPostProcessor 处理 @Async注解。这些注解都是在属性上或者方法上面。

3. 总结

  • BeanPostProcessor 接口主要是启动的时候添加到Spring容器中提供给后续的使用
  • BeanPostProcessor 接口执行主要发生在获取Bean的流程中(Bean的生命周期)
  • 自定义开发可以参照Spring已有的实现,能够更加明了的知道如何进行进一步拓展使用