天天看點

Spring容器重新整理—05-invokeBeanFactoryPostProcessors

作者:當年三歲半
Spring容器重新整理—05-invokeBeanFactoryPostProcessors

這次的内容是上圖中的第05步。

前言

通過前面幾篇文章的介紹,在整個容器重新整理過程中現在已經有了如下元件:

先來看看前面幾篇文章都做了什麼:

`01-prepareRefresh()`: `earlyApplicationListeners`、`applicationListeners` 、`initPropertySources()`、`validateRequiredProperties`
`02-obtainFreshBeanFactory()`: `refreshBeanFactory`
`03-prepareBeanFactory()`: `ignoreDependencyInterface`、`setBeanExpressionResolver`、`registerResolvableDependency`、`Environment`
`04-postProcessBeanFactory()`: 具體實作類的特殊邏輯(`Servlet` 等)           

本文所說的 invokeBeanFactoryPostProcessors 的作用是什麼呢?

這一步可以說:能對之前建立出來的 BeanFactory/BeanDefinitionRegistry 進行修改的最後機會了。

這一步完成之後,就要開始對 Bean 的建立做準備了。

invokeBeanFactoryPostProcessors

invokeBeanFactoryPostProcessors() 的源碼從 表面 看起來很簡單:

  • A. 調用了一個靜态方法 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
  • B. 如果不是 Native 鏡像環境的話就添加一些和類的動态增強相關的元件
public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {

    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        // 步驟A
        PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

        // 步驟B
        // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
        // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
        if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }
    }
}           

步驟 B 中所作的事情其實在 容器重新整理第二篇文章-prepareBeanFactory() 的時候就已經出現過了。大概意思就是初始化和 LoadTimeWeaver 相關的基礎元件。

LoadTimeWeaver

在Java中,類的加載通常是在應用程式啟動時完成的。 但是,有一些情況下需要在應用程式運作時加載類,而這就需要使用到 Load-Time Weaving 技術: 在類加載時通過 Instrumentation API 對類進行修改,以實作一些特定的功能,例如在運作時添加一些切面功能。

LoadTimeWeaver 不是本系列文章關注的重點,這裡暫時隻要知道步驟 B 的作用就行了。

重中之重是步驟 A 中的那個靜态方法。

前置知識

在分析靜态工具方法之前,我們要先明确幾個基本概念(如果已經了解可以直接跳過這部分)。

BeanFactoryPostProcessor

這個後置處理器是本文的重點。其作用就是提供一個對 BeanFactory 的擴充點。

  • 執行時機: BeanFactory 的标準初始化之後。所謂的标準初始化指的就是 prepareBeanFactory()。
  • 此時所有的 BeanDefinition 資訊都已經被加載
  • 但是,還沒有 Bean 執行個體被建立

可以在通過這個接口修改、替換、移除、新增 BeanDefinition,甚至是提前初始化 Bean(r如果有必要的話)。接口聲明如下:

public interface BeanFactoryPostProcessor {

    /**
     * Modify the application context's internal bean factory after its standard
     * initialization. All bean definitions will have been loaded, but no beans
     * will have been instantiated yet. This allows for overriding or adding
     * properties even to eager-initializing beans.
     * @param beanFactory the bean factory used by the application context
     * @throws org.springframework.beans.BeansException in case of errors
     */
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}           

BeanDefinitionRegistry

BeanDefinitionRegistry 就是 BeanDefinition 的系統資料庫: 提供了對 BeanDefinition 進行 CRUD 的接口。

需要知道的一點是各種 ApplicationContext 的實作都直接或間接實作了 BeanDefinitionRegistry。

public interface BeanDefinitionRegistry extends AliasRegistry {

    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException;

    void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    boolean containsBeanDefinition(String beanName);

    String[] getBeanDefinitionNames();

    int getBeanDefinitionCount();

    boolean isBeanNameInUse(String beanName);
}           

BeanDefinitionRegistryPostProcessor

BeanDefinitionRegistryPostProcessor 這個擴充接口有點特殊:

  • 繼承了 BeanFactoryPostProcessor: 也就是說可以通過他修改 BeanFactory
  • 同時擴充了一個方法 postProcessBeanDefinitionRegistry: 也就是說可以通過他修改 BeanDefinitionRegistry
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

    /**
     * Modify the application context's internal bean definition registry after its
     * standard initialization. All regular bean definitions will have been loaded,
     * but no beans will have been instantiated yet. This allows for adding further
     * bean definitions before the next post-processing phase kicks in.
     * @param registry the bean definition registry used by the application context
     * @throws org.springframework.beans.BeansException in case of errors
     */
    void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

}           

Ordered

上面提到的 BeanPostProcessor 可能有多個,那麼多個之間誰先執行呢?

要是實作了 Ordered 接口,就按照 `int getOrder()` 方法的順序執行,值越小越先執行。

public interface Ordered {
    int getOrder();
}           

PriorityOrdered

這個接口是 Ordered 接口的子接口,但是他的優先級在 Ordered 之前,就是說先執行完 PriorityOrdered 再執行 Ordered。

public interface PriorityOrdered extends Ordered {
}           

回調BeanFactoryPostProcessor

在開始分析 invokeBeanFactoryPostProcessors 這個靜态方法之前,還有個題外話。

題外話

在看 invokeBeanFactoryPostProcessors 之前,我們先看一下這個方法體中的注釋:

WARNING: Although it may appear that the body of this method can be easily refactored to avoid the use of multiple loops and multiple lists, the use of multiple lists and multiple passes over the names of processors is intentional. We must ensure that we honor the contracts for PriorityOrdered and Ordered processors. Specifically, we must NOT cause processors to be instantiated (via getBean() invocations) or registered in the ApplicationContext in the wrong order.
警告:盡管這個方法的主體看起來可以很容易地重構以避免使用多個循環和多個清單,但使用多個清單和多次周遊處理器名稱是有意的。 我們必須確定正确地處理 PriorityOrdered 和 Ordered 語義。 具體來說,我們不能導緻處理器以錯誤的順序被執行個體化(通過getBean()調用)或在ApplicationContext中注冊。
Before submitting a pull request (PR) to change this method, please review the list of all declined PRs involving changes to PostProcessorRegistrationDelegate to ensure that your proposal does not result in a breaking change: https://github.com/spring-projects/spring-framework/issues?q=PostProcessorRegistrationDelegate+is%3Aclosed+label%3A%22status%3A+declined%22
在送出 PR 更改此方法之前,請檢視所有已經被拒絕的用來更改 PostProcessorRegistrationDelegate 的 PR 清單,以確定您的 PR 不會導緻破壞性更改:。。。

大概意思是說:這個方法的實作看起來可能很容易被優化:去掉各種 "不必要的" 循環 和 "不必要的" List。

但是在你送出 PR 優化這個方法前先去 github 瞅瞅已經被拒絕掉的各種試圖修改改方法的 PR 清單……

源碼解析

現在真真正正進入重點内容:回調各種 BeanFactoryPostProcessor。流程有點複雜,重點都在下面代碼中的注釋。

final class PostProcessorRegistrationDelegate {

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

        // 這個寫在第一行的注釋 上面已經提到了  注意一下就行
        // WARNING: Although it may appear that the body of this method can be easily
        // refactored to avoid the use of multiple loops and multiple lists, the use
        // of multiple lists and multiple passes over the names of processors is
        // intentional. We must ensure that we honor the contracts for PriorityOrdered
        // and Ordered processors. Specifically, we must NOT cause processors to be
        // instantiated (via getBean() invocations) or registered in the ApplicationContext
        // in the wrong order.
        //
        // Before submitting a pull request (PR) to change this method, please review the
        // list of all declined PRs involving changes to PostProcessorRegistrationDelegate
        // to ensure that your proposal does not result in a breaking change:
        // https://github.com/spring-projects/spring-framework/issues?q=PostProcessorRegistrationDelegate+is%3Aclosed+label%3A%22status%3A+declined%22

        // 1. 首先調用各種 `BeanDefinitionRegistryPostProcessors`

        // 這個方法的目的不是為了調用 BeanFactoryPostProcessor 嗎? 為啥要先調用 `BeanDefinitionRegistryPostProcessors` ???
        // 這個方法的目的不是為了調用 BeanFactoryPostProcessor 嗎? 為啥要先調用 `BeanDefinitionRegistryPostProcessors` ???
        // 這個方法的目的不是為了調用 BeanFactoryPostProcessor 嗎? 為啥要先調用 `BeanDefinitionRegistryPostProcessors` ???

        // 可以了解為這一步是調用 `BeanDefinitionRegistryPostProcessors` 之前的前戲工作
        // 可以了解為這一步是調用 `BeanDefinitionRegistryPostProcessors` 之前的前戲工作
        // 可以了解為這一步是調用 `BeanDefinitionRegistryPostProcessors` 之前的前戲工作

        // Invoke BeanDefinitionRegistryPostProcessors first, if any.
        // 這個 set 裡儲存的就是 BeanName
        Set<String> processedBeans = new HashSet<>();

        // 提示: 如果你先去看看下面的 else 邏輯,再回頭看 if,可能會清晰一點
        // 提示: 如果你先去看看下面的 else 邏輯,再回頭看 if,可能會清晰一點
        // 提示: 如果你先去看看下面的 else 邏輯,再回頭看 if,可能會清晰一點

        // 不論是 if 還是 else,最終目的都是為了調用 invokeBeanFactoryPostProcessors
        // 但是 if 的邏輯在調用 invokeBeanFactoryPostProcessors之前,有一些特殊處理

        // beanFactory: 就是通過 BeanFactory 的标準初始化流程之後拿到 BeanFactory 執行個體
        // 1.1 如果目前 BeanFactory 是 BeanDefinitionRegistry 的子接口
        if (beanFactory instanceof BeanDefinitionRegistry) {
            BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
            // 正常的 BeanFactoryPostProcessor
            List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
            // 實作了 BeanDefinitionRegistryPostProcessor 的 BeanFactoryPostProcessor
            List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

            // 1.1.1 周遊所有的 BeanFactoryPostProcessor 
            // 将 `正常的 BeanFactoryPostProcessor` 和 `實作了 BeanDefinitionRegistryPostProcessor 的 BeanFactoryPostProcessor` 區分開來

            // 為什麼要将 `registryProcessors` 單獨拿出來
            // 因為 `registryProcessors` 是有修改 `BeanDefinitionRegistry` 的能力的

            // 在将兩者區分開來的同時 
            // 順便調用一下他的 `postProcessBeanDefinitionRegistry(registry);`
            // 因為畢竟他的 `postProcessBeanDefinitionRegistry()` 方法可能對 `BeanDefinitionRegistry` 做出修改
            // 比如某個 `registryProcessor` 可能給 `BeanDefinitionRegistry` 中新增或删除 `BeanDefinition`
            for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
                if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                    BeanDefinitionRegistryPostProcessor registryProcessor =
                            (BeanDefinitionRegistryPostProcessor) postProcessor;
                    registryProcessor.postProcessBeanDefinitionRegistry(registry);
                    registryProcessors.add(registryProcessor);
                } else {
                    // 正常的 BeanFactoryPostProcessor
                    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.
            List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

            // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
            String[] postProcessorNames =
                    beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            // 1.1.2 調用所有實作了 `PriorityOrdered` 接口  的 `BeanDefinitionRegistryPostProcessor`
            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, beanFactory.getApplicationStartup());
            currentRegistryProcessors.clear();

            // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            // 1.1.3 調用所有實作了 `Ordered` 接口  的 `BeanDefinitionRegistryPostProcessor`
            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, beanFactory.getApplicationStartup());
            currentRegistryProcessors.clear();

            // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
            // 1.1.4 調用其他的 `BeanDefinitionRegistryPostProcessor`(除了上面的特殊的兩種)
            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, beanFactory.getApplicationStartup());
                currentRegistryProcessors.clear();
            }

            // 經過上面一大波操作,最終就是為了調用 1.1.5 的邏輯。和 2.1 的邏輯類似
            // 經過上面一大波操作,最終就是為了調用 1.1.5 的邏輯。和 2.1 的邏輯類似
            // 經過上面一大波操作,最終就是為了調用 1.1.5 的邏輯。和 2.1 的邏輯類似
            // 1.1.5 回調所有 BeanFactoryPostProcessor 的 `postProcessBeanFactory()` 方法
            // Now, invoke the postProcessBeanFactory callback of all processors handled so far.
            invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
            invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
        } else {
            // 2. 如果目前 BeanFactory 不是 BeanDefinitionRegistry 的子接口
            // Invoke factory processors registered with the context instance.
            // 2.1 回調所有 BeanFactoryPostProcessor 的 `postProcessBeanFactory()` 方法
            invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
        }


        // 到目前為止,前戲已經做完了。現在可以開始調用 BeanFactoryPostProcessor 了
        // 到目前為止,前戲已經做完了。現在可以開始調用 BeanFactoryPostProcessor 了
        // 到目前為止,前戲已經做完了。現在可以開始調用 BeanFactoryPostProcessor 了

        // 2. 開始調用 BeanFactoryPostProcessor

        // 值得注意的是:這裡一直都是通過 getBeanNamesForType() 來操作的,并沒有直接 `getBean()`。就是避免某個 Bean 被提前執行個體化。
        // 為啥要避免提前執行個體化?這裡要是已經通過 getBean() 把執行個體建立出來了,那後續的 BeanPostProcessor 還怎麼增強 Bean ???

        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let the bean factory post-processors apply to them!
        // 所有 `BeanFactoryPostProcessor` 對應 BeanName
        String[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

        // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
        // Ordered, and the rest.
        // 2.1 将 BeanPostProcessor 分為三類:
        // A: 實作了 `PriorityOrdered` 接口的
        List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
        // B: 實作了 `Ordered` 接口的
        List<String> orderedPostProcessorNames = new ArrayList<>();
        // C: 普通的 BeanFactoryPostProcessor
        List<String> nonOrderedPostProcessorNames = new ArrayList<>();
        // 就是周遊一下  給 BeanFactoryPostProcessor 分個類
        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);
            }
        }

        // 上面的 for 中已經分類好了(A,B,C三類)
        // 現在就開始調用各種 BeanPostProcessor 了
        // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
        // 2.2 先調用實作了 `PriorityOrdered` 接口的 BeanPostProcessor
        sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
        invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

        // 2.2 再調用實作了 `Ordered` 接口的 BeanPostProcessor
        // 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);

        // 2.3 最後調用實作了正常的 BeanPostProcessor
        // 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();
    }
}