1. 程式人生 > 實用技巧 >Spring 原始碼學習 11:invokeBeanFactoryPostProcessors

Spring 原始碼學習 11:invokeBeanFactoryPostProcessors

前言

invokeBeanFactoryPostProcessors 會執行 BeanFactory 的後置處理器。看到這裡會有疑問:

  1. 什麼是 BeanFactoryPostProcessor ?
  2. BeanfactoryPostProcessor 該如何使用?

知道了上面兩個問題的答案,對 BeanFactoryPostProcessor 有了瞭解之後,然後再深入原始碼,繼續閱讀 invokeBeanFactoryPostProcessors 這個方法。

作用

資料還是在官網可以找到答案:

閱讀了一下,大概意思是 Spring IoC 容器允許 BeanFactoryPostProcessor 讀取配置元資料,並有可能在容器例項化除 BeanFactoryPostProcessor 例項以外的任何 bean 之前更改它。

同樣可以使用 Ordered 介面對 BeanFactoryPostProcessor 進行排序。

注意

BeanFactoryPostProcessor 操作的是 BeanDefinition ,即元資料。但是同樣可以通過獲取到 BeanFactory 進行例項化 Bean,但是官網很不建議這樣使用。

示例

使用 BeanFactoryPostProcessor

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

        // 修改 BeanDefinition 資訊
        BeanDefinition userComponentBeanDefinition = beanFactory.getBeanDefinition("userComponent");
        userComponentBeanDefinition.setLazyInit(true);

        // 修改 Bean 的資訊
        // xxx 非常不推薦 beanFactory.getBean 過早的例項化 Bean
        UserComponent bean = beanFactory.getBean(UserComponent.class);
        bean.setUserName("liuzhihang-01");
            
    }
}

建立自己的 BeanFactoryPostProcessor 並實現 BeanFactoryPostProcessor 介面,添加註解即可。

當然除了實現 BeanFactoryPostProcessor 介面,還有其他介面可以實現:

使用 BeanDefinitionRegistryPostProcessor

BeanDefinitionRegistryPostProcessor 繼承了 BeanFactoryPostProcessor,同時擴充套件了增加了 postProcessBeanDefinitionRegistry 方法。可以支援在 BeanDefinition 註冊之後 Bean 例項化之前對 BeanDefinition 進行操作。

@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 修改 BeanDefinition 資訊
        BeanDefinition userComponentBeanDefinition = beanFactory.getBeanDefinition("userComponent");
        userComponentBeanDefinition.setLazyInit(true);

        // 修改 Bean 的資訊
        // xxx 非常不推薦 beanFactory.getBean 過早的例項化 Bean
        UserComponent bean = beanFactory.getBean(UserComponent.class);
        bean.setUserName("liuzhihang-01");
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

        // 註冊一個 BeanDefinition
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(OrderComponent.class);

        AbstractBeanDefinition orderComponentBeanDefinition = builder.getBeanDefinition();

        registry.registerBeanDefinition("orderComponent", orderComponentBeanDefinition);

    }
}

下面是測試程式碼截圖:

OrderComponent 類沒有新增任何註解,然後註冊為 BeanDefinition 之後,從容器中可以獲取到 orderComponent。

如何修改欄位屬性

在 Spring 文件上說明,非常不建議在 BeanFactoryPostProcessor 中例項化 Bean,那這時候想修改 Bean 的資訊,改如何操作?

其實可以通過獲取到 MutablePropertyValues 後進行操作:

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

        // 修改 BeanDefinition 資訊
        BeanDefinition userComponentBeanDefinition = beanFactory.getBeanDefinition("userComponent");
        userComponentBeanDefinition.setLazyInit(true);

        MutablePropertyValues userComponentPropertyValues = userComponentBeanDefinition.getPropertyValues();

        userComponentPropertyValues.addPropertyValue("userName", "liuzhihang-02");

        // 修改 Bean 的資訊
        // xxx 非常不推薦 beanFactory.getBean 過早的例項化 Bean
        // UserComponent bean = beanFactory.getBean(UserComponent.class);
        // bean.setUserName("liuzhihang-01");

    }
}

invokeBeanFactoryPostProcessors

看完前面,我想已經知道了 BeanFactoryPostProcessor 是做什麼用的了,而這一步的主要作用就是例項化所有的 BeanFactoryPostProcessor。

進入原始碼:

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 (!IN_NATIVE_IMAGE && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }
}

其中 getBeanFactoryPostProcessors 方法獲取的是自己新增的 BeanFactoryPostProcessor。這句話是什麼意思呢?

public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
    return this.beanFactoryPostProcessors;
}

看原始碼,就是直接從 beanFactoryPostProcessors 獲取的,那如何向其中新增呢?

其實呼叫容器的 addBeanFactoryPostProcessor 方法即可。

繼續閱讀重點程式碼 invokeBeanFactoryPostProcessors

注意注意,這塊程式碼非常長!

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

    // Invoke BeanDefinitionRegistryPostProcessors first, if any.
    Set<String> processedBeans = new HashSet<>();

    // 判斷是否為 BeanDefinitionRegistry
    // debug 發現 這裡傳入的是 DefaultListableBeanFactory
    // DefaultListableBeanFactory 實現了 BeanDefinitionRegistry
    if (beanFactory instanceof BeanDefinitionRegistry) {
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;

        // 建立了兩個 List 集合, 用來存放處理器
        // BeanDefinitionRegistryPostProcessor 是 BeanFactoryPostProcessor 的子介面
        // BeanDefinitionRegistryPostProcessor 還可以額外處理 BeanDefinition, 新增 BeanDefinition
        // 用法可以參考示例
        List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
        List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

        // 迴圈 beanFactoryPostProcessors
        // beanFactoryPostProcessors 是使用 API context.addBeanFactoryPostProcessor 新增進來的
        for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {

            // BeanDefinitionRegistryPostProcessor 要單獨新增到 registryProcessors
            if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                BeanDefinitionRegistryPostProcessor registryProcessor =
                        (BeanDefinitionRegistryPostProcessor) postProcessor;

                // 處理 Bean 的資訊
                registryProcessor.postProcessBeanDefinitionRegistry(registry);
                registryProcessors.add(registryProcessor);
            } else {
                regularPostProcessors.add(postProcessor);
            }
        }

        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let the bean factory post-processors apply to them!
        // Separate between BeanDefinitionRegistryPostProcessors that implement
        // PriorityOrdered, Ordered, and the rest.
        // 上面迴圈是執行的我們呼叫 API 新增的 BeanDefinitionRegistryPostProcessor
        // 下面執行 Spring 自己的 BeanDefinitionRegistryPostProcessor 集合
        // 先執行實現了 PriorityOrdered介面的,然後是 Ordered 介面的,最後執行剩下的
        List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

        // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
        // 第一步先呼叫 BeanDefinitionRegistryPostProcessors 它實現了PriorityOrdered
        // 在初始化 reader 時 在註冊了 ConfigurationClassPostProcessor 到容器裡面
        // BeanDefinitionRegistryPostProcessor 實現了 BeanDefinitionRegistryPostProcessor
        String[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        for (String ppName : postProcessorNames) {
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                // 新增 bean
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                // 這裡只添加了名字 後面用來判斷誰已經執行過了
                processedBeans.add(ppName);
            }
        }
        // 排序
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);

        // 迴圈執行 processors 的 postProcessBeanDefinitionRegistry 方法
        // 這個得在仔細看
        // debug 看到 執行完這一步我另一個加 @Component 註解的類 註冊到 Registry 裡面了
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
        // 清除
        currentRegistryProcessors.clear();

        // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
        // 處理實現 Ordered 的 processor
        postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        for (String ppName : postProcessorNames) {
            // 只有不包含的才執行, 執行完之後會新增進 processedBeans
            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, beanFactory.getApplicationStartup());
        currentRegistryProcessors.clear();

        // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
        // 最後執行其他
        boolean reiterate = true;
        while (reiterate) {
            reiterate = false;
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                // 只有不包含的才執行, 執行完之後會新增進 processedBeans
                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, beanFactory.getApplicationStartup());
            currentRegistryProcessors.clear();
        }

        // Now, invoke the postProcessBeanFactory callback of all processors handled so far.
        // 上面處理的都是 postProcessBeanDefinitionRegistry 是在 -> BeanDefinitionRegistryPostProcessor 中
        // 下面開始處理 postProcessBeanFactory  -> 是在 BeanFactoryPostProcessor 中
        invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
        invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
    } else {
        // Invoke factory processors registered with the context instance.
        // 不是 BeanDefinitionRegistry 則是普通 BeanFactory 直接執行 beanFactoryPostProcessors 即可
        invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
    }

    // Do not initialize FactoryBeans here: We need to leave all regular beans
    // uninitialized to let the bean factory post-processors apply to them!

    // 第二部分
    // 上面執行的是 BeanDefinitionRegistryPostProcessor
    // 下面開始執行 BeanFactoryPostProcessor
    String[] postProcessorNames =
            beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

    // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
    // Ordered, and the rest.
    // 按照順序執行
    List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    List<String> orderedPostProcessorNames = new ArrayList<>();
    List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    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);
        }
    }

    // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
    // 執行實現 PriorityOrdered 的
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

    // Next, invoke the BeanFactoryPostProcessors that implement 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);

    // Finally, invoke all other BeanFactoryPostProcessors.
    List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
    for (String postProcessorName : nonOrderedPostProcessorNames) {
        nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

    // Clear cached merged bean definitions since the post-processors might have
    // modified the original metadata, e.g. replacing placeholders in values...
    // 清空不必要的元資料資訊
    beanFactory.clearMetadataCache();
}

上面總體可以分為兩部分:

  1. 執行 BeanDefinitionRegistryPostProcessor 接口裡面的兩個方法:postProcessBeanDefinitionRegistry 和 postProcessBeanFactory。
  2. 執行 BeanFactoryPostProcessor 接口裡面的 postProcessBeanFactory 方法。

以第一部分為例:

  1. 首先判斷傳入的 BeanFactory 是否為 BeanDefinitionRegistry
    1. 宣告兩個 List 集合,regularPostProcessors 用來儲存 BeanFactoryPostProcessor,registryProcessors 用來儲存 BeanDefinitionRegistryPostProcessor
      1. 迴圈 beanFactoryPostProcessors,這個就是我們使用 API 方式新增進來的 BeanFactoryPostProcessor。
      2. 在迴圈中 BeanDefinitionRegistryPostProcessor 的 postProcessBeanDefinitionRegistry 會被執行,也就是說我示例的那個新增 BeanDefinition 演示的方法會被執行。
    2. 開始執行 Spring 自己的 BeanDefinitionRegistryPostProcessor, 處理順序為 PriorityOrdered, Ordered, and the rest
      1. 迴圈,將對應的 BeanDefinitionRegistryPostProcessor 新增到 currentRegistryProcessors 集合和processedBeans集合表示為已經處理。
      2. 排序後新增到第一步的 registryProcessors 中。
      3. 呼叫 invokeBeanDefinitionRegistryPostProcessors 執行所有的 Processor 裡面的 postProcessBeanDefinitionRegistry 方法
    3. 執行完 1 和 2 之後,所有的 postProcessBeanDefinitionRegistry 已經被執行完了,但是兩個集合(registryProcessors、regularPostProcessors)裡面的 postProcessBeanFactory 方法還沒有被執行。最後會迴圈執行。
  2. 如果不是 BeanDefinitionRegistry 型別,則直接執行傳入的 beanFactoryPostProcessors 即可。

下面是對應的程式碼截圖

以上只是這個方法的前半部分,執行了 BeanDefinitionRegistryPostProcessor 裡面的 postProcessBeanDefinitionRegistry 和 postProcessBeanFactory。

因為還有直接實現 BeanFactoryPostProcessor 的處理器,下面則開始處理 BeanFactoryPostProcessor 的處理器。過程和上面類似。

總結

通過以上的閱讀,對 invokeBeanFactoryPostProcessors(beanFactory); 這一步方法進行總結。

BeanFactoryPostProcessor 作用

BeanFactoryPostProcessor 主要作用是在註冊 BeanDefinition 之後,在 Bean 初始化之前,修改 BeanDefinition 的資訊。

BeanFactoryPostProcessor 有個實現叫 BeanDefinitionRegistryPostProcessor,它可以額外的註冊新的 BeanDefinition 到容器中。

流程概述

  1. 這一步主要是處理 BeanFactoryPostProcessor,分為兩步。
  2. 執行 BeanDefinitionRegistryPostProcessor 接口裡面的兩個方法:postProcessBeanDefinitionRegistry 和 postProcessBeanFactory。
  3. 執行 BeanFactoryPostProcessor 接口裡面的 postProcessBeanFactory 方法。

相關推薦