Spring BeanPostProcessor执行顺序问题
Spring Framework版本:5.3.x
BeanPostProcessor
在Spring框架中举足轻重,还有很多继承的类。
作用:管理Bean的生命周期:Bean实例化--->Bean初始化--->Bean使用中--->Bean销毁
在Spring 容器初始化的时候就会存在这些类执行的一个先后的问题,今天我们就把这些类的执行先后顺序进行梳理。
1. 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容器销毁而销毁的。整个执行的流程和步骤如下图:
从上图的执行顺序可以看出来:
接口之间的执行顺序不是严格按照: 实例化->初始化->销毁 这样的严格顺序来进行。接口方法之间的顺序会有穿插的情况。
InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 方法执行如果返回了对应的Bean的实例,后续的接口都不会执行了。
这里我们可以加入自定义的类。典型的例子就是动态代理的实现,可以继承当前接口并且在改方法中实现动态代理。这样在Spring 容器中的实例就是一个动态代理实例。
DestructionAwareBeanPostProcessor 接口一般情况下是不会执行,只有当Spring容器销毁就会触发容器里面类的销毁机制。
同一种类型接口如果有继承 PriorityOrdered 和Ordered进行排序。
Tips: 对于基于BeanPostProcessor自定义开发来说,主要用于自定义方法或者属性类上面的注解。这里举两个Spring的例子:AutowiredAnnotationBeanPostProcessor 处理@Autowired, @Value注解, AsyncAnnotationBeanPostProcessor 处理 @Async注解。这些注解都是在属性上或者方法上面。
3. 总结
BeanPostProcessor 接口主要是启动的时候添加到Spring容器中提供给后续的使用
BeanPostProcessor 接口执行主要发生在获取Bean的流程中(Bean的生命周期)
自定义开发可以参照Spring已有的实现,能够更加明了的知道如何进行进一步拓展使用
作者:蚂蚁背大象
链接:https://juejin.cn/post/7056330983125024776