天天看點

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