0
点赞
收藏
分享

微信扫一扫

Spring Framework 源码阅读(五):BeanFactoryPostProcessor


Spring Framework 源码阅读(五):BeanFactoryPostProcessor

在上一篇博客中介绍了​​BeanPostProcessor​​​和​​Bean​​​的生命周期,​​BeanPostProcessor​​​是允许自定义修改新​​bean​​​实例的工厂钩子,在新​​bean​​​实例初始化前后调用​​BeanPostProcessor​​​中的方法,而通过​​FactoryBean​​​创建的新​​bean​​​实例和​​Spring​​​通过反射创建的新​​bean​​​实例在应用​​BeanPostProcessor​​​方面有所不同,前者只会调用​​BeanPostProcessor​​​中的​​postProcessAfterInitialization​​​方法,而后者会调用​​BeanPostProcessor​​中的所有方法,想详细了解这些内容可以阅读这篇博客:

  • ​​Spring Framework 源码阅读(四):BeanPostProcessor和Bean的生命周期​​

那​​BeanFactoryPostProcessor​​​有啥用?看命名跟​​BeanPostProcessor​​​差不多,其实功能也差不多,都是自定义修改实例,只是修改的主体不同,​​BeanPostProcessor​​​修改的主体是​​bean​​​,而​​BeanFactoryPostProcessor​​​修改的主体是​​bean​​​定义,不了解​​bean​​定义,可以阅读这篇博客:

  • ​​Spring Framework 源码阅读(二):BeanDefinition的作用​​

注意,​​BeanFactoryPostProcessor​​​和​​BeanPostProcessor​​​都是自定义修改实例(实例主体不同),在两者应用时,实例肯定是已经实例化了(通过反射调用或者​​FactoryBean​​直接调用这两种方式,调用了实例类的构造函数)。

​BeanFactoryPostProcessor​​​接口源码如下(​​@FunctionalInterface​​​表示该接口是函数式接口,可以使用​​lambda​​表达式直接赋值):

@FunctionalInterface
public interface BeanFactoryPostProcessor {

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

  • 工厂钩子:允许自定义修改应用程序上下文(​​application context​​​)的 ​​bean​​​ 定义,调整上下文底层 ​​bean​​​ 工厂的 ​​bean​​​ 属性值。对于自定义配置文件很有用,这些文件覆盖了应用程序上下文中配置的 ​​bean​​​ 属性。 有关满足此类配置需求的开箱即用解决方案,请参阅​​PropertyResourceConfigurer​​​及其具体实现。​​BeanFactoryPostProcessor​​​可以与​​bean​​​定义交互并修改​​bean​​​定义,但绝不能与​​bean​​​实例交互(这样做可能会导致 ​​bean​​​过早实例化、违反容器意愿并导致意外的副作用)。 如果需要与​​bean​​​实例交互,请考虑实现​​BeanPostProcessor​​ 。
  • 注册:​​ApplicationContext​​​在其​​bean​​​定义中自动检测​​BeanFactoryPostProcessor bean​​​,并在创建任何其他​​bean​​​之前应用它们。 ​​BeanFactoryPostProcessor​​​也可以通过​​ConfigurableApplicationContext​​以编程方式注册。
  • 顺序:在​​ApplicationContext​​​中自动检测的​​BeanFactoryPostProcessor bean​​​将根据​​PriorityOrdered​​​和​​Ordered​​​语义进行排序。 相比之下,使用​​ConfigurableApplicationContext​​​以编程方式注册的​​BeanFactoryPostProcessor bean​​​将按注册顺序应用; 对于以编程方式注册的​​PostProcessor​​​,通过实现​​PriorityOrdered​​​或​​Ordered​​​接口表达的任何排序语义都将被忽略。 此外,​​@Order​​​注解不会被​​BeanFactoryPostProcessor bean​​考虑在内。

博主早期的博客,可能排版不好看以及语言不严谨,也推荐阅读一下,可以对函数式接口(​​@FunctionalInterface​​)有一个直观的认识。

  • ​​JDK8 新特性Function接口​​

创建module

先在​​Spring Framework​​​源码中增加一个​​application module​​,这在之前的博文中已经介绍过了,这里就不再赘述:

  • ​​编译 Spring Framework 5.2.17源码 & 在源码中使用 ApplicationContext 获取定义的Bean​​

Spring Framework 源码阅读(五):BeanFactoryPostProcessor_后端


​TaskBeanDefinitionProcess​​​类(实现​​BeanFactoryPostProcessor​​接口):

package com.kaven.process;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

import java.util.Objects;

/**
* @Author: ITKaven
* @Date: 2021/11/03 10:34
* @Leetcode: https://leetcode-cn.com/u/kavenit
* @Notes:
*/

@Component
public class TaskBeanDefinitionProcess implements BeanFactoryPostProcessor {

// 将自定义的作用域字符串myScope转换成singleton
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition bd = beanFactory.getBeanDefinition("myTask");
if(Objects.equals(bd.getScope(), "myScope")) {
bd.setScope("singleton");
}
}
}

启动类​​Application​​:

package com.kaven;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.*;

import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;

/**
* @Author: ITKaven
* @Date: 2021/09/25 13:54
* @Leetcode: https://leetcode-cn.com/u/kavenit
* @Notes:
*/

@ComponentScan({"com.kaven"})
public class Application {

public static void main(String[] args) {
// 创建应用上下文
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 在应用上下文中添加BeanFactoryPostProcessor
// 将myTask bean的BeanDefinition的懒加载设置为false
applicationContext.addBeanFactoryPostProcessor((beanFactory) -> {
beanFactory.getBeanDefinition("myTask").setLazyInit(false);
});

// 注册组件类
applicationContext.register(Application.class);

// refresh
applicationContext.refresh();

// 获取myTask bean
Task task = (Task) applicationContext.getBean("myTask");
System.out.println("taskCount: " + task.addTask());

// 获取myTask bean的BeanDefinition
BeanDefinition taskBeanDefinition = applicationContext.getBeanDefinition("myTask");
System.out.println(taskBeanDefinition.getScope());
System.out.println(taskBeanDefinition.isLazyInit());

// 获取应用上下文中的BeanDefinition数量和名称
System.out.println("BeanDefinitionCount: " + applicationContext.getBeanDefinitionCount());
Arrays.stream(applicationContext.getBeanDefinitionNames()).forEach(System.out::println);
}

// myTask bean
@Bean(value = "myTask")
@Scope("myScope")
@Lazy
public Task getTask() {
return new Task();
}

public static class Task{
private final AtomicInteger taskCount;

public Task() {
taskCount = new AtomicInteger(0);
}

public int addTask() {
return taskCount.incrementAndGet();
}
}
}

输出结果:

taskCount: 1
singleton
false
BeanDefinitionCount: 7
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
application
taskBeanDefinitionProcess
myTask

很显然符合预期,​​myTask bean​​​的作用域从自定义作用域字符串​​myScope​​​转换成了​​singleton​​​,懒加载也设置成了​​false​​​,这些都是因为​​TaskBeanDefinitionProcess​​​类的​​postProcessBeanFactory​​​方法以及下方的​​lambda​​表达式起作用了。

(beanFactory) -> {
beanFactory.getBeanDefinition("myTask").setLazyInit(false);
}

源码分析

开始​​Debug​​。

Spring Framework 源码阅读(五):BeanFactoryPostProcessor_后端_02


Spring Framework 源码阅读(五):BeanFactoryPostProcessor_后端_03


执行这行代码:

applicationContext.refresh();

调用了​​AbstractApplicationContext​​​抽象类的​​refresh​​方法(删除了部分代码):

@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备此上下文以进行刷新
prepareRefresh();

// 告诉子类刷新内部bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// 准备在此上下文中使用的bean工厂
prepareBeanFactory(beanFactory);

try {
// 允许在上下文子类中对bean工厂进行postProcess
postProcessBeanFactory(beanFactory);

// 调用在上下文中注册的BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);

// 注册BeanPostProcessor
registerBeanPostProcessors(beanFactory);

// 初始化此上下文的消息源
initMessageSource();

// 为此上下文初始化事件多播器
initApplicationEventMulticaster();

// 初始化特定上下文子类中的其他特殊bean
onRefresh();

// 检查监听器bean并注册它们
registerListeners();

// 实例化所有剩余的(非延迟加载)单例
finishBeanFactoryInitialization(beanFactory);

// 发布相应的事件
finishRefresh();
}
}
}

之后会调用​​PostProcessorRegistrationDelegate​​​类的​​invokeBeanFactoryPostProcessors​​方法(删除了部分代码,看注释即可):

public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

// 如果有的话,首先调用BeanDefinitionRegistryPostProcessor
Set<String> processedBeans = new HashSet<>();

if (beanFactory instanceof BeanDefinitionRegistry) {

// 调用BeanDefinitionRegistryPostProcessor
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();

// 调用到目前为止处理的所有处理器的postProcessBeanFactory回调
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// 调用在上下文实例中注册的BeanFactoryPostProcessor
// 但beanFactory不能instanceof BeanDefinitionRegistry
// 如果beanFactory instanceof BeanDefinitionRegistry
// 执行上面的invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory)
// 也会调用在上下文实例中注册的BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}

// 获取BeanFactoryPostProcessor bean的名称
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

// 调用BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

// 清除缓存的合并bean定义
// 因为BeanFactoryPostProcessor可能已经修改了原始元数据,例如替换值中的占位符
beanFactory.clearMetadataCache();
}

​BeanDefinitionRegistryPostProcessor​​接口源码:

// 对标准BeanFactoryPostProcessor SPI的扩展
// 允许在常规BeanFactoryPostProcessor检测开始之前注册bean定义
// 特别是, BeanDefinitionRegistryPostProcessor可以注册BeanFactoryPostProcessor bean定义。
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

// 在标准初始化之后修改应用程序上下文的内部bean定义注册表
// 所有常规bean定义都将被加载,但尚未实例化任何bean
// 这允许在下一个后处理阶段开始之前添加更多的bean定义
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

}

所以,​​BeanFactoryPostProcessor​​​应用时,​​bean​​定义已经注册好了,和前面描述的一致。

但我们并没有提供​​BeanDefinitionRegistryPostProcessor​​​接口的实现,为什么还能注册​​bean​​​定义?还记得代码的输出结果中有几个​​Spring​​​内置的​​bean​​定义:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory

​org.springframework.context.annotation.internalConfigurationAnnotationProcessor​​​对应的​​bean​​​类是​​ConfigurationClassPostProcessor​​类。

这在​​BeanDefinition​​的作用这篇博客中有介绍。

/**
* 内部管理Configuration注解的处理器的bean名称
*/
public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalConfigurationAnnotationProcessor";

if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}

​ConfigurationClassPostProcessor​​​类(实现了​​BeanDefinitionRegistryPostProcessor​​接口):

// 这个PostProcessor是优先级排序的,因为在任何其他BeanFactoryPostProcessor执行之前
// 在@Configuration类中声明的任何@Bean方法都必须注册其相应的bean定义,这一点很重要
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
...
}

当然我们这里没有使用​​@Configuration​​​注解,但很显然​​@ComponentScan({"com.kaven"})​​的效果也是类似的。

再回到​​PostProcessorRegistrationDelegate​​​类的​​invokeBeanFactoryPostProcessors​​​方法,通过​​Debug​​​,可以知道在调用​​invokeBeanFactoryPostProcessors​​​方法前,如下图所示的​​5​​​个​​bean​​​定义就已经注册了,这在​​BeanDefinition​​​的作用这篇博客中有介绍,这里不再赘述。所以,还剩下​​myTask​​​和​​taskBeanDefinitionProcess​​​这两个​​bean​​​的​​bean​​定义没有注册。

Spring Framework 源码阅读(五):BeanFactoryPostProcessor_spring_04


调用了​​ConfigurationClassPostProcessor​​​类的​​postProcessBeanDefinitionRegistry​​​方法后,​​myTask​​​和​​taskBeanDefinitionProcess​​​这两个​​bean​​​的​​bean​​定义也会被注册。

Spring Framework 源码阅读(五):BeanFactoryPostProcessor_spring_05


而​​myTask bean​​​的​​bean​​​定义还没有被修改,因为自定义的两个​​BeanFactoryPostProcessor​​还没有应用。

Spring Framework 源码阅读(五):BeanFactoryPostProcessor_初始化_06


在这里会应用使用​​lambda​​​表达式定义的​​BeanFactoryPostProcessor​​​(​​beanFactory instanceof BeanDefinitionRegistry​​​为​​true​​​,不然下面​​else​​​部分那一行代码也会执行该​​BeanFactoryPostProcessor​​)。

Spring Framework 源码阅读(五):BeanFactoryPostProcessor_自定义_07


Spring Framework 源码阅读(五):BeanFactoryPostProcessor_后端_08

懒加载设置成了​​false​​​,而作用域还是自定义的作用域字符串​​myScope​​。

Spring Framework 源码阅读(五):BeanFactoryPostProcessor_java_09


在这里会应用我们实现的​​BeanFactoryPostProcessor​​​(​​TaskBeanDefinitionProcess​​类)。

Spring Framework 源码阅读(五):BeanFactoryPostProcessor_后端_10


Spring Framework 源码阅读(五):BeanFactoryPostProcessor_spring_11


到这里作用域也修改成功了。

Spring Framework 源码阅读(五):BeanFactoryPostProcessor_spring_12


​BeanFactoryPostProcessor​​​能被应用,说明这些​​BeanFactoryPostProcessor bean​​​已经创建好了(能修改其他​​bean​​​的​​bean​​​定义,当然需要提取创建好,以便应用,当然使用​​lambda​​​表达式定义的​​BeanFactoryPostProcessor​​不需要被创建,类似使用匿名内部类,本身就是一个实例,只是原理有些不同):

Spring Framework 源码阅读(五):BeanFactoryPostProcessor_java_13


​invokeBeanFactoryPostProcessors​​方法开始执行时,还没有已经创建的对象。

Spring Framework 源码阅读(五):BeanFactoryPostProcessor_自定义_14


执行完下面这部分代码,​​ConfigurationClassPostProcessor​​​类对应的​​bean​​​就被创建好了(通过​​beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)​​​创建),该​​bean​​​也会注册之前说过的那两个​​bean​​定义。

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();

Spring Framework 源码阅读(五):BeanFactoryPostProcessor_后端_15


执行完下面这部分代码,​​BeanFactoryPostProcessor bean​​​(​​TaskBeanDefinitionProcess​​​实例)也创建好了(通过​​beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class)​​创建)。

List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}

Spring Framework 源码阅读(五):BeanFactoryPostProcessor_后端_16


通过上面的分析,可以知道​​BeanFactoryPostProcessor​​​可以用于注册​​bean​​​定义以及修改​​bean​​​定义等,修改​​bean​​​定义时,这些​​bean​​​定义已经注册到了​​bean​​工厂中。

阅读源码需要耐心,一步步进行​​Debug​​,每个人的理解不同,如果博主有说错的地方或者大家有不同的见解,欢迎大家评论补充。


举报

相关推荐

0 条评论