这是我参与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、@Ordered1.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 普通类:没有任何特殊注解或者加了
@Import3.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的提前实例化。