前言
如果说spring里面哪个代码最有意思,我觉得,非本篇要谈的invokeBeanFactoryPostProcessors方法不可?为什么我会这么觉得,因为,这段代码,第一次看,可能会觉得很多相似的、甚至一模一样的地方,感觉很冗余。但仔细研究后,就会发现里面考虑很多情况,甚至这些逻辑会让阅读源码的人,好像行走在迷宫里。今天,我尝试着用我的方法,带着迷失在这一大段源码海洋里的人,走出来。
了解几个增强器相关的接口
我们先了解两个十分重要的接口BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor。 看下源码中的定义。
BeanFactoryPostProcessor
接口
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
BeanDefinitionRegistryPostProcessor
接口
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
- BeanFactoryPostProcessor:对BeanFactory的增强处理,关于这个接口的扩展,我们会单独用一篇文章详细说明。
- BeanDefinitionRegistryPostProcessor:与BeadDefinition相关的增强器,继承自BeanFactoryPostProcessor。除了继承的增强BeanFactory功能外,还能够实现动态的将Bean注册到Spring容器中。
BeanDefinitionRegistry
及其上下游的主要相关类的继承结构图。
下图是
BeanDefinitionRegistry
上下游的主要相关类的继承结构图。从这张图我们可以看出DefaultListableBeanFactory
是BeanDefinitionRegistry
的实现类。 该类定义了一组对BeanDefinition增删改查等基本操作的接口规范。 至于图中其他类的具体情况,有兴趣的小伙伴可以参考图中说明,并结合源码,自行分析即可。
了解几个顺序相关的接口
Ordered
接口
public interface Ordered {
int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;
int LOWEST_PRECEDENCE = Integer.MAX_VALUE;
int getOrder();
}
PriorityOrdered
接口
public interface PriorityOrdered extends Ordered {
}
上面两个接口,是用来反映对象的优先级别。Ordered接口中定义了顺序的上下限,以及获取顺序的方法,getOrder()返回的值越小,优先级越高。
PriorityOrdered
继承自Ordered
,没有定义任何规范,它的优先级要高于Ordered
。
上面简单描述了优先级的两个接口所约定的规范,那么Spring中一般是如何来保证这一规范得以实现的呢?这就要看下面的接口OrderComparator
OrderComparator
顺序比较器
public class OrderComparator implements Comparator<Object> {
@Override
public int compare(@Nullable Object o1, @Nullable Object o2) {
return doCompare(o1, o2, null);
}
private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderSourceProvider sourceProvider) {
boolean p1 = (o1 instanceof PriorityOrdered);
boolean p2 = (o2 instanceof PriorityOrdered);
if (p1 && !p2) {
return -1;
}
else if (p2 && !p1) {
return 1;
}
int i1 = getOrder(o1, sourceProvider);
int i2 = getOrder(o2, sourceProvider);
return Integer.compare(i1, i2);
}
public static void sort(List<?> list) {
if (list.size() > 1) {
list.sort(INSTANCE);
}
}
public static void sort(Object[] array) {
if (array.length > 1) {
Arrays.sort(array, INSTANCE);
}
}
public static void sortIfNecessary(Object value) {
if (value instanceof Object[]) {
sort((Object[]) value);
}
else if (value instanceof List) {
sort((List<?>) value);
}
}
// 其他方法。略
}
- 在该类中,定义并实现了3个静态排序方法:sort(List<?> list)、sort(Object[] array)、sortIfNecessary(Object value),用来实现数组和集合进行排序。
- doCompare:该方法保证了Ordered接口所定义规范的落实。通过该源码我们也可以证实,对两个对象而言:
- 实现了不同的排序接口的:实现PriorityOrdered的优先级高于实现Order的对象;实现Order接口的对象,其优先级高于未实现任何排序接口的对象。
- 实现了同一个排序接口的(Ordered或者PriorityOrdered):比较getOrder()返回值,值越小、优先级越高。 对于我们今天要讨论的invokeBeanFactoryPostProcessors()方法,是通过优先获取PriorityOrdered、再获取Ordered等来保证处理顺序的(这两类接口内部再根据order排序)
既然这里提到了BeanDefinitionRegistry,那么就简单提一下BeanDefinition及相关类的继承结构图,方便对照学习。如下所示:
invokeBeanFactoryPostProcessors
委派执行
下面进入今天的主题,invokeBeanFactoryPostProcessors()方法的执行流程。
该方法的实现,实际上是委托给了PostProcessorRegistrationDelegate类,如下。当我们基于配置文件的方式完成注入时,参数beanFactory的实际类型为DefaultListableBeanFactory
,这是个有故事的类,我们后面会多次遇到,会慢慢道尽。Bean定义相关的两个重要属性Map和List就藏在这个类里面,所以可以说这是个宝藏类。
AbstractApplicationContext.java
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// 委托了给类进行实现的
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
PostProcessorRegistrationDelegate
下面是本方法真正的核心部分。由于总体上逻辑比较长,这里使用总分总的说明方式来叙述。
方法的总体结构设计
我这里将源码掏空,只保留总体的流程框架和步骤编号,如下
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors)
// 默认进入if逻辑
// 第一块
if (beanFactory instanceof BeanDefinitionRegistry) {
// 步骤1.1:处理方法参数beanFactoryPostProcessors
// 步骤1.2:从所有的BeanDefinitionRegistryPostProcessor实现类中筛选出、实现了PriorityOrdered接口的类, 并处理和标记
// 步骤1.3:从所有未被标记的BeanDefinitionRegistryPostProcessor实现类中筛选出、实现了Ordered接口的类, 并处理和标记
// 步骤1.4:循环获取、所有未被标记的BeanDefinitionRegistryPostProcessor实现类,并处理和标记
// 步骤1.5 执行BeanFactoryPostProcessor的postProcessBeanFactory()方法
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
} else {
// 直接执行
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// 下面是第二块
// 步骤2.1:从所有的BeanFactoryPostProcessor实现类中筛选出、实现了PriorityOrdered接口的类, 并处理和标记
// 步骤2.2:从所有未被标记的BeanFactoryPostProcessor实现类中筛选出、实现了Ordered接口的类, 并处理和标记
// 步骤2.3:从所有未被标记的BeanFactoryPostProcessor实现类,并处理和标记
}
下面通过一张流程图,将上面涉及到的核心步骤抽象出来
通过上面的源码和流程图可以看出来,作者在处理时,优先处理的是第一块中的子类,然后再在第二块中去处理父类。这两个接口的继承关系在本篇的开头部分已经给出来说明。这里的第一块和第二块、主角分别是BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor
分别说明每个步骤
第一块
- 步骤1.1
第一块的代码,默认会进入if里的流程,这里简单再回顾一下,由于传入的第一个参数beanFactory的实际类型
DefaultListableBeanFactory
是BeanDefinitionRegistry
的实现类,所以会进入if的逻辑之中。
下面给出步骤1.1中的源码
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);
}
}
代码如上。在前面的小节,我们分析了BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor这两个接口,前者是后者的子接口。
在该步骤中,遍历方法的第二个参数beanFactoryPostProcessors,找出子类和父类,并归档。同时,直接完成了子类中方法的调用。父类中的方法在后面会统一调用。
- 找出BeanDefinitionRegistryPostProcessor这个子接口的所有实现,放入registryProcessor集合;并完成该接口中独有的方法postProcessBeanDefinitionRegistry()的调用;
- 找出BeanFactoryPostProcessor这个父接口的所有实现,归档存入regularPostProcessors集合。
- 步骤1.2
从所有的BeanDefinitionRegistryPostProcessor实现类中筛选出、实现了PriorityOrdered接口的类, 并处理和标记。 源码如下:
// 步骤1.2
// BeanDefinitionRegistryPostProcessor && PriorityOrdered
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);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
// 加入到registryProcessors集合中
registryProcessors.addAll(currentRegistryProcessors);
// 完成调用处理逻辑
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
// 处理完毕, 同样清除掉, 给下次再次使用
currentRegistryProcessors.clear();
这里需要先明确几个变量的作用:
Set<String> processedBeans:处理过的Processor, 放入该集合。其实就是一个标记作用,防止在遍历和过滤的时候,重复处理。
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors:我们在前面总的结构了分成了1.1、1.2、1.3等很多小步骤、这个集合的作用就是保存每一个小步骤中要处理的资源。每个步骤结束后该集合就要重置。
List<BeanDefinitionRegistryPostProcessor> registryProcessors:在步骤1.1中已经见过了,存放的是实现了registryProcessors的Processor实例。
步骤1.2的大致过程如下:
- 找到所有的BeanDefinitionRegistryPostProcessor
- 遍历、并筛选出实现了PriorityOrdered接口的PostProcessor
- 实例化筛选出来的PostProcessor(通过getBean()方法)
- 进行标记和统一处理
- 步骤1.3 该步骤和1.2类型,区别在于,这次的顺序主角换成了Ordered,直接上源码
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
// 从未标记过的postProcessorNames中, 筛选出实现了PriorityOrdered的
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
// 完成调用处理逻辑
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
// 处理完毕, 同样清除掉, 给下次再次使用
currentRegistryProcessors.clear();
- 步骤1.4 来看源码:
boolean reiterate = true;
while (reiterate) {
reiterate = false;
// 再根据类型获取一遍, 得到名称集合
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
// 上面没过滤到的漏网之BeanDefinitionRegistryPostProcessor, 放在这里进行实例化
// 其实就是没排序的Processor, 这个做兜底处理
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
// 并且把标记需要在循环一次,因为之后新的BeanDefinitionRegistryPostProcessor的调用可能注册新的BeanDefinitionRegistryPostProcessor
reiterate = true;
}
}
// 排序、收集、调用
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
// 同样完成调用执行
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
// 照例进行清除
currentRegistryProcessors.clear();
该步骤是来处理剩下的、未进行排序的postProcessor,该步骤和上面的1.2、1.3有所不同,此处使用了一个循环,原因在于BeanDefinitionRegistryPostProcessor中定义的规范:void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry), 通过参数registry可以实现动态的BeanDefinition的注册,因此只要实现BeanDefinitionRegistryPostProcessor接口,就可以实现新的BeanDefinition的注册。而新注册的这个类,也可能实现了BeanDefinitionRegistryPostProcessor接口,因此,这里需要循环获取,直到找不到为止。在文末,会赋上一个例子,方便理解。
- 步骤1.5 该步骤只有两行代码,即调用了所有实现BeanFactory的postProcessBeanFactory()方法,源码如下
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
- 第一个逻辑块总结
- 遍历方法的第二个参数,找到BeanDefinitionRegistryPostProcessor的实现类,并完成由该接口定义的方法postProcessBeanDefinitionRegistry(registry); 剩下的实例, 为BeanFactoryPostProcessor的实现类, 存入集合
- 找出所有的BeanDefinitionRegistryPostProcessor、且实现了PriorityOrdered接口的类, 并 "处理"
- 找出剩下的BeanDefinitionRegistryPostProcessor、且实现了Ordered接口的类, 并"处理"
- 循环找出剩下的所有的BeanDefinitionRegistryPostProcessor的类, 并"处理
- 最后, 在调用父类BeanFactoryPostProcessor的方法postProcessBeanFactory(...)
- 这里的每一个步骤中的 "处理", 主要操作指的是:排序、调用子接口中的postProcessBeanDefinitionRegistry()方法
第二块
- 步骤2.1 ~ 步骤2.3 由于这三步与第一块处理方式基本一致,且要简单很多,这里我简单进行说明。源码如下。
// 第二块:
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
} else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
} else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
} else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// 步骤2.1 BeanFactoryPostProcessor && priorityOrdered
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 步骤2.2 BeanFactoryPostProcessor && Ordered
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// 步骤2.3 BeanFactoryPostProcessor && 无序
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
- 这里将获取的对象从
BeanDefinitionRegistryPostProcessor
变为了BeanFactoryPostProcessor
,其他的处理方式都是按照PriorityOrdered
、Ordered
、nonOrdered
这个顺序进行了处理。- invokeBeanFactoryPostProcessors(..):由于这里的对象为BeanFactoryPostProcessor, 所以这个方法调用即为
postProcessBeanFactory()
方法
总结
我们用一张图总结这个方法。
文末
前面提到了为什么在步骤1.4处,需要用循环获取,这里给出一个实例。
说明:XXXXX01方法中,以代码的方式动态注册了一个XXXXX02类型的实例:bb,并且XXXXX02这个类也实现了接口BeanDefinitionRegistryPostProcessor。
说明:XXXXX01和XXXXX02都实现了BeanDefinitionRegistryPostProcessor。在XXXXX01方法中注册了一个BeanDefinition:bb, 类型为XXXXX02,而类XXXXX02也是一个BeanDefinitionRegistryPostProcessor实现类。当我们在获取到。正如上面所说:策略增强器的方法中注册的类,又是一个实现了该增强器的类,那就需要再次获取了,所以是不是明白为什么需要循环获取了?
public class MyBeanDefinitionRegistryPostProcessor01 implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 通过该方法注册一个实例, 且注册的实例又实现了BeanDefinitionRegistryPostProcessor接口
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(MyBeanDefinitionRegistryPostProcessor02.class);
registry.registerBeanDefinition("bb", definition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
public class MyBeanDefinitionRegistryPostProcessor02 implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 仍然可以通过registry再次注册一个BeanDefinition
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
spring.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="myBeanDefinitionRegistryPostProcessor01" class="xxx.xxx.MyBeanDefinitionRegistryPostProcessor01" />
</beans>
测试类:
public class App {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring.xml");
MyBeanDefinitionRegistryPostProcessor01 bean01 = context.getBean(MyBeanDefinitionRegistryPostProcessor01.class);
MyBeanDefinitionRegistryPostProcessor02 bean02 = (MyBeanDefinitionRegistryPostProcessor02) context.getBean("bb");
System.out.println(bean01);
System.out.println(bean02);
}
}