天天看点

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
Spring Framework 源码阅读(五):BeanFactoryPostProcessor

执行这行代码:

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

调用了​

​ConfigurationClassPostProcessor​

​​类的​

​postProcessBeanDefinitionRegistry​

​​方法后,​

​myTask​

​​和​

​taskBeanDefinitionProcess​

​​这两个​

​bean​

​​的​

​bean​

​定义也会被注册。

Spring Framework 源码阅读(五):BeanFactoryPostProcessor

而​

​myTask bean​

​​的​

​bean​

​​定义还没有被修改,因为自定义的两个​

​BeanFactoryPostProcessor​

​还没有应用。

Spring Framework 源码阅读(五):BeanFactoryPostProcessor

在这里会应用使用​

​lambda​

​​表达式定义的​

​BeanFactoryPostProcessor​

​​(​

​beanFactory instanceof BeanDefinitionRegistry​

​​为​

​true​

​​,不然下面​

​else​

​​部分那一行代码也会执行该​

​BeanFactoryPostProcessor​

​)。

Spring Framework 源码阅读(五):BeanFactoryPostProcessor
Spring Framework 源码阅读(五):BeanFactoryPostProcessor

懒加载设置成了​

​false​

​​,而作用域还是自定义的作用域字符串​

​myScope​

​。

Spring Framework 源码阅读(五):BeanFactoryPostProcessor

在这里会应用我们实现的​

​BeanFactoryPostProcessor​

​​(​

​TaskBeanDefinitionProcess​

​类)。

Spring Framework 源码阅读(五):BeanFactoryPostProcessor
Spring Framework 源码阅读(五):BeanFactoryPostProcessor

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

Spring Framework 源码阅读(五):BeanFactoryPostProcessor

​BeanFactoryPostProcessor​

​​能被应用,说明这些​

​BeanFactoryPostProcessor bean​

​​已经创建好了(能修改其他​

​bean​

​​的​

​bean​

​​定义,当然需要提取创建好,以便应用,当然使用​

​lambda​

​​表达式定义的​

​BeanFactoryPostProcessor​

​不需要被创建,类似使用匿名内部类,本身就是一个实例,只是原理有些不同):

Spring Framework 源码阅读(五):BeanFactoryPostProcessor

​invokeBeanFactoryPostProcessors​

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

Spring Framework 源码阅读(五):BeanFactoryPostProcessor

执行完下面这部分代码,​

​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

执行完下面这部分代码,​

​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