这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战
BeanFactoryPostProcessor
是spring
中一个很重要的扩展点,它与BeanPostProcessor
长相类似,触发点略有不同。BeanFactoryPostProcessor
的作用时期是在所有bean
实例化之前。所以它的作用是加载BeanDefinition
。或者可以动态的修改或者是新增BeanDefinition
。
类图
BeanFactoryPostProcessor
有一个扩展接口,这个扩展接口的方法会优先与BeanFactoryPostProcessor
的方法执行。
源码
还是从spring
的核心方法refresh
入手。其中的invokeBeanFactoryPostProcessors(beanFactory);
就是用来处理BeanFactoryPostProcessor
。spring
的refresh
在之前的文章中有介绍,这边就不展开。
1.调用BeanFactoryPostProcessor
---> (在这里执行!!!)
@Override
public void refresh() throws BeansException, IllegalStateException {
// ...
invokeBeanFactoryPostProcessors(beanFactory);
// ...
}
核心的处理方法在PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
,源码处已有一些注释。这里简单描述一下整个流程。
第一步:参数中传递进来的 beanFactoryPostProcessors
,由上述可知,这里可能是BeanDefinitionRegistryPostProcessor
也可能是BeanFactoryPostProcessor
的实现类。所以定义两个集合regularPostProcessors
和registryProcessors
用于将二者分离开。这里会执行参数中传递进来的BeanDefinitionRegistryPostProcessor
类型的接口。(在springboot
中,可以在启动类的启动方法中添加)
第二步:获取容器中所有的BeanDefinitionRegistryPostProcessor
,挑选出包含实现了PriorityOrdered
接口的类,根据特定的排序规则进行排序后逐一执行。(在默认的情况下,这里仅会获取到ConfigurationClassPostProcessor
,这里类的作用是处理配置类,将配置类[也就是开发者标记@Configuration
、@Component
、@ImportSelector
等等]添加到容器中。)
第三步:获取容器中所有的BeanDefinitionRegistryPostProcessor
,挑选出包含实现了Ordered
接口的类,过滤执行过BeanDefinitionRegistryPostProcessor
(若某个接口同时实现Ordered
和PriorityOrdered
,则应该在第二步中执行),根据特定的排序规则进行排序后逐一执行。
第四步:获取容器中所有的BeanDefinitionRegistryPostProcessor
,过滤已经执行过的,将剩下未执行的所有类,根据特定的排序规则进行排序后逐一执行。(这里使用死循环的原因:可能出现套娃情况,某个BeanDefinitionRegistryPostProcessor
的实现方法中又创建了一个新的BeanDefinitionRegistryPostProcessor
。)
以上便已经执行了容器中所有BeanDefinitionRegistryPostProcessor
的扩展点。接下来就是执行BeanFactoryPostPostProcessor
扩展点。
第五步:执行上述所有步骤中的BeanDefinitionRegistryPostProcessor
的BeanFactoryPostProcessor
的实现接口。(就是扩展接口中的扩展方法已经都执行完了,在这个地方统一执行父接口中的实现方法。)
第六步:执行参数中传递进来的beanFactoryPostProcessors
中仅实现BeanFactoryPostProcessor
的实现接口。
第七步:(BeanFactoryPostPostProcessor
的执行比较简单,用一步概括),获取容器中所有实现了BeanFactoryPostProcessor
的类,将它们分为三类PriorityOrdered
、Ordered
、和没有实现这两个接口的。然后分别根据排序规则进行排序后逐一执行。
-
执行
BeanDefinitionRegistryPostProcessor
的扩展点1.1 执行参数
beanFactoryPostProcessors
中是BeanDefinitionRegistryPostProcessor
的实现类的扩展点1.2 执行
spring
容器中的BeanDefinitionRegistryPostProcessor
的实现且依次@PriorityOrdered、@Ordered
1.3执行容器中还存在
BeanDefinitionRegistryPostProcessor
实现但未加入已执行集合(registryProcessors
)中的实现类 -
执行
BeanDefinitionPostProcessor
的扩展点2.1执行非直接实现
BeanDefinitionRegistryPostProcessor
集合(registryProcessors
)的BeanFactoryPostProcessor
的扩展点2.2执行直接实现
BeanFactoryPostProcessor
集合(regularPostProcessors
)的BeanFactoryPostProcessor
的扩展点(这个集合中若存在元素, 则是开发者通过调用参数携带进来, 在第一步骤执行是分离出来)2.3执行
spring
容器中还未执行的BeanFactoryPostProcessor
、顺序依次为@PriorityOrdered
、@Ordered
、最后是没有标记前者两注解的BeanFactoryPostProcessor
的实现类。beanFactoryPostProcessors
这个是自定义的beanFactoryPostProcessors
, 默认是空的, 除非自己扩展。
①.处理过的BeanDefinitionRegistryPostProcessors
类型的bean
名字集合
②.常规postProcessor
(直接实现BeanFactoryPostProcessor
的实现类)集合
③.registryProcessor
(非直接实现BeanFactoryPostProcessor
的实现类)且已经调用过扩展点的集合
④.BeanFactoryPostProcessor
是BeanDefinitionRegistryPostProcessor
的父接口, 执行beanFactoryPostProcessors
中的BeanDefinitionRegistryPostProcessor
并将执行过后的BeanDefinitionRegistryPostProcessor
放置在registryProcessors
, 将未执行的BeanFactoryPostProcessor
添加到regularPostProcessors
⑤.调用BeanDefinitionRegistryPostProcessor
扩展点
⑥.直接实现了BeanFactoryPostProcessor
接口的实现
⑦.放内部的BeanDefinitionRegistryPostProcessor
后置处理器
⑧.首先, 调用实现了PriorityOrdered
接口的BeanDefinitionRegistryPostProcessors
(若没有改造或者二次开发过, 此处只会返回ConfigurationClassPostProcessor
类ConfigurationClassPostProcessor
类的作用是加载配置类)
⑨.调用processedBeans
中没有标记过的BeanDefinitionRegistryPostProcessors
这个while
循环是由于可能出现套娃的情况: 比如A类实现了BeanDefinitionRegistryPostProcessor
, 在调用A的
postProcessBeanDefinitionRegistry
中又添加了一个BeanDefinitionRegistryPostProcessor
类B。
⑩.不要在此处初始化 FactoryBeans
:我们需要保留所有未初始化的常规bean
,让 bean
工厂后处理器应用于它们!
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// ①
Set<String> processedBeans = new HashSet<>();
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// ②
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
// ③
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
// ④
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor;
// ⑤
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}else {
// ⑥
regularPostProcessors.add(postProcessor);
}
}
// ⑦
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// ⑧
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
registryProcessors.addAll(currentRegistryProcessors);
// 执行BeanDefinitionRegistryPostProcessors扩展点
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// 调用仅实现了Ordered接口的BeanDefinitionRegistryPostProcessors
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
// 过滤调用过的processedBean
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
// ...
}
}
// ⑨.
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
// ...
}
}
}
}
// ⑩
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
}
例子
从spring
的生命周期看BeanFactoryPostProcessor
的执行时机就是在BeanPostProcessor
注册之前,甚至可以说是在大部分的bean
注入之前。但若大量使用BeanFactoryPostProcessor
进行扩展,若有重叠区域,则需考虑执行的先后顺序。比如后期的扩展是否需要控制新的BeanFactoryPostProcessor
要在旧BeanFactoryPostProcessor
之前或者之后?这个执行顺序是一个很容易忽略的关键点(自定义的BeanFactoryPostProcessor
可以通过实现Order
接口控制执行顺序)
实例1
可以通过BeanDefinitionRegistryPostProcessor
修改BeanDefinition
,比如在业务场景中有非常多的地方使用的是名称注入的方式,现要让这个名称注入容器中的类由新类,替换旧类。
扫描项目路径下的旧类,进行class
替换,并使其指向新类。
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
BeanDefinition beanDefinition = registry.getBeanDefinition("roomService");
beanDefinition.setBeanClassName("cn.com.xiaocainiaoya.service.NewRoomService");
}
}
实例2
springframwork
的扫描工作中比较核心的类ConfigurationClassPostProcessor
,这个类的作用就是扫描配置类,扫描指定路径下的各种配置注解@Configuration
、Component
、ComponentScan
等等。将这些类解析后添加到BeanDefinition
中。
以下方法的主要作用为从注册表中的配置类派生进一步的bean
定义,简单说根据beanDefinition
将配置类添加到spring
容器中。
执行的顺序为:
-
完成扫描
-
对配置类的定义,完成对配置类的标记
-
对
import
的处理3.1
ImportSelector
(在springboot
中自动装配典型使用)3.2
ImportBeanDefinitionRegistrar
(在mybatis
中典型使用)3.3 普通类:没有任何特殊注解或者加了
@Import
3.4
ImportResource
-
@Bean
的处理 -
接口中的
@bean
-
@PropertySource
的处理 -
内部类的处理
-
父类的处理
说明:
①.表示此registry
里的BeanDefinition
收集动作,避免再重复收集此registry
②.根据配置类,收集到所有的bd
信息,并且做出mark
标注:是Full
模式还是Lite
模式
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
// ...
// ①
this.registriesPostProcessed.add(registryId);
// ②
processConfigBeanDefinitions(registry);
}
注意事项
BeanFactoryPostProcessor
算是spring
给予开发者很高的权限去处理BeanDefinitions
,但使用的过程中还需遵守spring
的规范,不可将bean
实例化,即不可在BeanFactoryPostProcessor
中触发bean
实例化的操作。比如:
1.这个getBeansOfType调用会触发getBean方法,会导致Bean提前注入,而在生命周期的这个节点自动注入的BeanPostProcessor
还没有注入,还不会作用在bean
的创建过程中,所以会导致
RoomService
的属性注入会失效。
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 1.
Map<String, RoomService> map = beanFactory.getBeansOfType(RoomService.class);
}
}
所以,在BeanFactoryPostProcessor
的使用中切记要确保不会触发Bean
的提前实例化。