在spring中BeanFactoryPostProcessor的执行是非常重要的一部分,无论是扫描的实现还是拓展spring都需要涉及到这部分。BeanFactoryPostProcessor的执行时机是在BeanFactory实例化之后,可以修改beanFactory。
BeanFactoryPostProcessor是spring提供的一个接口,其内部只有一个方法:
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
BeanFactoryPostProcessor还有一个子接口BeanDefinitionRegistryPostProcessor,其内部添加了一个方法:
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
这2个接口都很重要,在下文中约定:;下文提到的。
这里介绍一些BeanFactoryPostProcessor与BeanDefinitionRegistryPostProcessor的实现类。
这个类非常重要,其实现了BeanDefinitionRegistryPostProcessor接口与PriorityOrdered接口:
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware
其相关方法如下:
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
/**
* @author lcy
* 处理配置beanDefinition
*/
processConfigBeanDefinitions(registry);
}
就是在这个方法里将配置类指定的类解析为BeanDefinition对象,并放入BeanFactory的beanDefinitionMap中。
还有一点需要说明,这个类是在执行AnnotationConfigApplicationContext的无参构造方法时被解析为beanDefinition并放入map中的。
为了测试执行流程,我自己写了3个相关后置处理器:
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor
public class ParamBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor
并重写了相应方法,用于打印一些标记。
为了易于表述和理解,下文中遵循以下约定:
在AnnotationConfigApplicationContext的refresh()内部的
invokeBeanFactoryPostProcessors(beanFactory)
完成了对
BeanFactoryPostProcessor对象与BeanDefinitionRegistryPostProcessor对象相关方法的执行。该方法具体逻辑如下:
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
在这个方法内,最重要的就是第一行代码,需要注意到,这一行代码的第二个参数:getBeanFactoryPostProcessors(),其结果一般是空,除非在执行这行代码前,程序员向容器中添加了BeanFactoryPostProcessor实现类的对象或BeanDefinitionRegistryPostProcessor实现类的对象。添加方式如下:
AnnotationConfigApplicationContext ac=new AnnotationConfigApplicationContext();
ac.register(AppConfig.class);
//向容器中添加一个后置处理器
ac.addBeanFactoryPostProcessor(new ParamBeanDefinitionRegistryPostProcessor());
ac.refresh();
可以看到,我在ac.refresh()前向容器中添加了一个ParamBeanDefinitionRegistryPostProcessor对象。接下来详解下面的方法:
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
Set processedBeans = new HashSet<>();
这个集合里存放执行过postProcessBeanDefinitionRegistry()的对象(不包括参数中的)的name。
List regularPostProcessors = new ArrayList<>();
这个集合存放参数中的BeanFactoryPostProcess对象。
List registryProcessors = new ArrayList<>();
这个集合存放所有执行过postProcessBeanDefinitionRegistry()的对象(包括参数中的)。
List currentRegistryProcessors = new ArrayList<>();
这个集合存放马上要执行postProcessBeanDefinitionRegistry()的BeanDefinitionRegistryPostProcessor对象。
List priorityOrderedPostProcessors = new ArrayList<>();
这个集合存放实现了PriorityOrdered接口的BeanFactoryPostProcessor对象。
List orderedPostProcessorNames = new ArrayList<>();
这个集合存放实现了Ordered接口的BeanFactoryPostPrpocessor对象的name。
List nonOrderedPostProcessorNames = new ArrayList<>();
这个集合存放未实现PriorityOrdered与Ordered接口的BeanFactoryPostProcessor对象的name。
以上变量都非常重要,但是其具体作用此处无法表述,在具体的执行逻辑中,会分析其作用。
首先会针对所有的BeanDefinitionRegistryPostProcessor对象进行处理,其内部有2个方法,相关执行顺序如下:
先执行的是所有BeanDefinitionRegistryPostProcessor对象的postProcessBeanDefinitionRegistry()。依据对象来源及信息不同,执行顺序如下:
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
可以看到,如果是BeanDefinitionRegistryPostProcessor对象,则执行相应的方法,并将其加入到registryProcessors这个集合中,否则(也就是说是BeanFactoryPostProcessor子类),则将其加入到regularPostProcessors这个集合中。
通过debug可以看到,遍历的beanFactoryPostProcessors中就只有我们之前添加的ParamBeanDefinitionRegistryPostProcessor对象。
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.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
首先,从beanFactory中拿到所有BeanDefinitionRegistryPostProcessor对象的name,然后从中选择实现了PriorityOrdered的。接下来,拿到name对应的bean,将bean放入currentRegistryProcessors集合中,同时将name放入processedBeans集合中。需要注意到,在getBean()执行完成后,所提到的对象就一定真正产生了,而且还成为了一个bean。
在循环执行完后,currentRegistryProcessors中就存放了刚才循环中找到的合适的BeanDefinitionRegistryPostProcessor对象一般情况下,这里找到的就是ConfigurationClassPostProcessor对象。
接下来会针对currentRegistryProcessors中存放的对象排序,并将所有对象存放到registryProcessors这个集合中。在此之后,就会真正执行currentRegistryProcessors中所有对象的postProcessBeanDefinitionRegistry(),而ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry()中完成的功能之一就是扫描,也就是说,在执行完这一行代码后,例如加了@Component的组件(类)就会被扫描、解析成BeanDefinition对象存入beanDefinitionMap中。最后,在将currentRegistryProcessors集合清空,以便下次使用。
这里会有一个问题,为什么需要先将合适的对象存放到currentRegistryProcessors中,而不是直接在找到其后便直接执行呢?在结尾我会谈谈我对这个问题的看法。
在方法执行前,可以看到beanDefinitionMap中只有一些spring内置的类与AppConfig类的BeanDefinition对象。前面提到过,spring内置的这些是在AnnotationConfigApplicationContext的无参构造方法中添加进去的,也正是因为beanDefinitionMap中存在ConfigurationClassPostProcessor对应的BeanDefinition,在beanFactory.getBeanNamesForType()中才能拿到其name。而AppConfig是在AnnotationConfigApplicationContext的register()中注册进去的。
与上一张图对比,可以看到beanDefinitionMap中增加了几个beanDefiniiton,而我提供的2个加了@Component的后置处理器也在其中。可以证明,就是在这里完成的扫描。
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
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();
这里的执行逻辑与上一步几乎相同,但是有几点需要说明:
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
这段代码与上面的差别也不大,这里就其中的差异谈谈:
在前面几步,所有BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()已经全部执行过了,但是由于BeanDefinitionRegistryPostProcessor是继承了BeanFactoryPostProcessor
所以其内部还有postProcessBeanFactory()需要执行。
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
在之前的执行中,每个执行过postProcessBeanDefinitionRegistry()的BeanDefinitionRegistryPostProcessor对象都被放进registryProcessors集合中,所以只需要将这个集合中的对象的postProcessBeanFactory()执行一遍就可以了。而且执行顺序与这些对象的postProcessBeanDefinitionRegistry()执行顺序一致。
通过debug可以清楚的看到registryProcessors内的对象与这些对象的顺序。
BeanFactoryPostProcessor对象只有postProcessBeanFactory()这一个方法需要执行,下面详细说明其执行顺序与逻辑。
之前有提到,如果参数中的是BeanFactoryPostProcessor对象,则直接放入regularPostProcessors集合中。所以,只需要将这个集合中对象的postProcessBeanFactory()执行一遍即可。
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
这里就体现了regularPostProcessors保存参数中BeanFactoryPostProcessor对象的作用及意义。
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
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);
}
}
首先,先从容器中拿到所有BeanFactoryPostProcessor对象的name,注意此时那些BeanDefinitionRegistryPostProcessor对象的name也会被拿出来。然后循环这些map,按以下情况分别处理:
那么,又有一个问题来了,直接拿PriorityOrdered接口的对象可以理解,毕竟马上就要执行。那么,为什么对于Ordered接口和未实现其他接口的对象只是拿name,而不是顺便也把对象拿出来?我会在结尾谈谈我的理解。
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
这个地方比较简单,就是先对priorityOrderedPostProcessors集合中对象排序,然后遍历执行其中对象的postProcessBeanFactory方法。
List orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
由于之前已经获得了相应的name,这里就是获得orderedPostProcessorNames中name对应的对象,然后对这些对象排序,并依次执行其postProcessBeanFactory()。
List nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
这一段就很好理解,就是通过name获得对象并保存起来,然后统一执行对象的postProcessBeanFactory()。
上文中提到过2个问题,分别是currentRegistryProcessors的作用和为什么对于非PriorityOrdered对象最开始只是拿name。为了解决这2个问题,先要明确一个点,那就是后置处理器可能对beanFactory做出修改,而通过getBean()获得的对象是由beanFactory产生的,也就是说,执行过的后置处理器会影响之后后置处理器的创建。
这里总结一下:保证同一优先级的后置处理器彼此互不影响,而高优先级的后置处理器影响低优先级后置处理器对象的创建。