天天看點

Spring容器重新整理—06-register-bean-post-processors

作者:當年三歲半
Spring容器重新整理—06-register-bean-post-processors

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

前言

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

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

`01-prepareRefresh()`: `earlyApplicationListeners`、`applicationListeners` 、`initPropertySources()`、`validateRequiredProperties`
`02-obtainFreshBeanFactory()`: `refreshBeanFactory`
`03-prepareBeanFactory()`: `ignoreDependencyInterface`、`setBeanExpressionResolver`、`registerResolvableDependency`、`Environment`
`04-postProcessBeanFactory()`: 具體實作類的特殊邏輯(`Servlet` 等)
`05-invokeBeanFactoryPostProcessors()`: 可能發生的對 `BeanFactory/BeanDefinitionRegistry` 的修改操作           

也就是說,現在的 BeanFactory 已經完全準備好了,通過正常途徑已經無法修改 BeanFactory 了。

接下來就要開始考慮單例 Bean 的初始化了,但是在此之前,還有好多的準備工作。

第一個準備工作就是本文要說的 registerBeanPostProcessors()。

registerBeanPostProcessors() 隻是注冊各種 BeanPostProcessor,還遠遠沒到 BeanPostProcessor 執行的時候。

前置知識

看 registerBeanPostProcessors() 方法的名字就是要注冊 BeanPostProcessor 了,那麼先來了解一下 BeanPostProcessor 是什麼。

BeanPostProcessor 是一個鈎子函數,用來修改新建立的 Bean 執行個體,比如 檢測标記在 Bean 上的标記接口或用代理對象包裝 Bean。BeanPostProcessor 還有一系列的擴充子接口。

Spring容器重新整理—06-register-bean-post-processors

下面就介紹幾種常見的 BeanPostProcessor。

BeanPostProcessor

public interface BeanPostProcessor {

    /**
     * 在任何 「Bean初始化方法」(比如說InitializingBean#afterPropertiesSet) 回調之前, 将該 BeanPostProcessor 應用于一個給定的新的Bean執行個體.
     *
     * 此處傳入的 Bean 已經經過 populateBean 填充屬性了.
     * 傳回的 bean 執行個體可能是對原始bean的包裝.
     * 預設實作: 原樣傳回給定的 Bean
     *
     * 如果傳回 null, 則不會調用後續的 BeanPostProcessors.
     *
     * @return 原始對象或者對原始對象的包裝;
     */
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    /**
     * 在任何 「Bean初始化方法」(比如說InitializingBean#afterPropertiesSet) 回調之後, 将該 BeanPostProcessor 應用于一個給定的新的Bean執行個體.
     *
     * 此處傳入的 Bean 已經經過 populateBean 填充屬性了.
     * 傳回的 bean 執行個體可能是對原始bean的包裝.
     *
     * 對于 FactoryBean 的情況而言,該回調方法既可以對 FactoryBean 執行個體本身回調, 也可以對 FactoryBean 傳回的對象回調(從 Spring 2.0 開始).
     * 具體實作可以自己決定是否回調 FactoryBean 執行個體 或/和 FactoryBean 傳回的執行個體.
     *
     * 與其他的回調方法不同, 該回調方法也可以被 InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 觸發
     *
     * 預設實作: 原樣傳回給定的 Bean
     *
     * 如果傳回 null, 則不會調用後續的 BeanPostProcessors.
     *
     * @return 原始對象或者對原始對象的包裝;
     */
    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

}           

InstantiationAwareBeanPostProcessor

InstantiationAwareBeanPostProcessor 是 BeanPostProcessor 的子接口,主要擴充了如下的方法:

  • 擴充了一個在 Bean 執行個體化 之前的回調
  • 擴充了一個在 Bean 執行個體化 之後, 但在 Bean 填充屬性或自動裝配發生之前的回調

一般用于攔截特定目标對象的預設執行個體化,比如建立(池化、懶加載等)代理對象。或者實作特定的注入政策,比如字段注入。

該接口是一個特殊接口,主要在架構内部使用。一般場景,建議盡可能實作簡單的 BeanPostProcessor 接口。而不是使用該接口。
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

    /**
     * 在目标bean執行個體化之前回調該BeanPostProcessor.
     *
     * 傳回的bean對象可能是代理對象,而不是目标bean,進而攔截了目标bean的預設執行個體化.
     *
     * 如果該方法傳回了非空對象,則目前bean的建立過程将被短路.
     * 短路之後唯一會被進一步調用的是來自BeanPostProcessors的postProcessAfterInitialization方法。
     *
     * 預設實作: 傳回 null
     *
     * @return 代理對象 或 傳回null以繼續Bean的預設執行個體化流程
     */
    @Nullable
    default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        return null;
    }

    /**
     * 回調時機: Bean 被[執行個體化]之後(構造器或工廠方法),但在spring填充屬性或自動裝配之前
     *
     * 這裡是實作使用者自定義字段注入的完美時機,剛好在 spring 的自動注入之前.
     *
     * 預設實作: return true
     *
     * @return true: 表示應該給目前Bean填充屬性;
     * false: 對目前Bean的屬性填充應該被跳過;
     *
     * 傳回false還會阻止在目前bean執行個體上回調任何後續的InstantiationAwareBeanPostProcessor執行個體。
     */
    default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        return true;
    }

    /**
     * 在工廠将給定的屬性值應用于給定的bean之前,對目前Bean進行處理
     *
     * 如果具體實作類提供來自定義的postProcessPropertyValues實作,則應傳回null(預設值),否則傳回pvs
     *
     * @return the actual property values to apply to the given bean (can be the passed-in
     * PropertyValues instance), or {@code null} which proceeds with the existing properties
     * but specifically continues with a call to {@link #postProcessPropertyValues}
     * (requiring initialized {@code PropertyDescriptor}s for the current bean class)
     */
    @Nullable
    default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
            throws BeansException {

        return null;
    }

    /**
     * Post-process the given property values before the factory applies them
     * to the given bean. Allows for checking whether all dependencies have been
     * satisfied, for example based on a "Required" annotation on bean property setters.
     * <p>Also allows for replacing the property values to apply, typically through
     * creating a new MutablePropertyValues instance based on the original PropertyValues,
     * adding or removing specific values.
     * <p>The default implementation returns the given {@code pvs} as-is.
     * @param pvs the property values that the factory is about to apply (never {@code null})
     * @param pds the relevant property descriptors for the target bean (with ignored
     * dependency types - which the factory handles specifically - already filtered out)
     * @param bean the bean instance created, but whose properties have not yet been set
     * @param beanName the name of the bean
     * @return the actual property values to apply to the given bean (can be the passed-in
     * PropertyValues instance), or {@code null} to skip property population
     * @throws org.springframework.beans.BeansException in case of errors
     * @see #postProcessProperties
     * @see org.springframework.beans.MutablePropertyValues
     * @deprecated as of 5.1, in favor of {@link #postProcessProperties(PropertyValues, Object, String)}
     */
    @Deprecated
    @Nullable
    default PropertyValues postProcessPropertyValues(
            PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {

        return pvs;
    }

}           

DestructionAwareBeanPostProcessor

DestructionAwareBeanPostProcessor 是 Bean 被銷毀之前的回調接口。所謂的銷毀指的是: DisposableBean.destroy()、 destroy-method 等。

public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {

    /**
     * Bean 被銷毀之前回調
     */
    void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;

    /**
     * 目前 Bean 是否需要被銷毀
     * @since 4.3
     */
    default boolean requiresDestruction(Object bean) {
        return true;
    }

}           

registerBeanPostProcessors

這一步就是給 BeanFactory 中注冊各種 BeanPostProcessor,那麼最終注冊到哪裡去了呢?

addBeanPostProcessor

看看下面的 addBeanPostProcessors() 和 addBeanPostProcessor() 方法就明白了。

值得注意的是,這兩個方法雖然名字看起來是 add,但是實際上他的作用應該是: removeAndAddToLast 的意思,就是每次先删掉之前的,再将新增的放到最後。

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {

    private final List<BeanPostProcessor> beanPostProcessors = new BeanPostProcessorCacheAwareList();

    public void addBeanPostProcessors(Collection<? extends BeanPostProcessor> beanPostProcessors) {
        this.beanPostProcessors.removeAll(beanPostProcessors);
        this.beanPostProcessors.addAll(beanPostProcessors);
    }

    @Override
    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
        Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
        // Remove from old position, if any
        this.beanPostProcessors.remove(beanPostProcessor);
        // Add to end of list
        this.beanPostProcessors.add(beanPostProcessor);
    }
}           

繼續看 registerBeanPostProcessors(),實際上最終是委托給了 PostProcessorRegistrationDelegate.registerBeanPostProcessors(ConfigurableListableBeanFactory, AbstractApplicationContext) 這個工具方法。

源碼流程

方法剛開始還是和上一篇介紹的 invokeBeanFactoryPostProcessors 一樣,來了一大波提示資訊,大概意思是:

這個方法看起來寫的很啰嗦,好像很容易優化。但是在你優化之前先瞅瞅 github 已經被拒絕的的 PR 清單……
final class PostProcessorRegistrationDelegate {
    public static void registerBeanPostProcessors(
            ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

        // 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

        // 這裡依然是小心翼翼僅僅擷取了 BeanPostProcessor 類型的 beanName,還不能調用 getBean()
        String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

        // Register BeanPostProcessorChecker that logs an info message when
        // a bean is created during BeanPostProcessor instantiation, i.e. when
        // a bean is not eligible for getting processed by all BeanPostProcessors.

        // beanFactory.getBeanPostProcessorCount(): 目前 BeanFactory 中已經存在的 BeanPostProcessor 數量
        // +1: 加的 1 就是 `BeanPostProcessorChecker` 自己
        // postProcessorNames.length: 指的是在下面一大波循環中要新增到 BeanFactory 中的 BeanPostProcessor
        int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;

        // BeanPostProcessorChecker就是來檢測: 在 BeanPostProcessor 初始化的過程中有沒有導緻普通的 Bean 初始化
        // 如果有: 就列印一堆資訊提醒你, 有 Bean 被過早初始化了

        // 為什麼要提醒: 因為現在還在建立 BeanPostProcessor,
        // 但是這個過程中你突然建立了一個普通 Bean,
        // 那麼你這個過早被建立的普通 Bean 可能無法被 BeanPostProcessor 增強(比較 BeanPostProcessor 自己都還在建立過程中呢)
        beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

        // 還是老套路: 将 BeanPostProcessor 分類(4大類)

        // 需要注意的是第1類和第2類是通過 getBean 建立出來的執行個體,其他兩類都是 beanName(避免過早執行個體化)
        // 需要注意的是第1類和第2類是通過 getBean 建立出來的執行個體,其他兩類都是 beanName(避免過早執行個體化)
        // 需要注意的是第1類和第2類是通過 getBean 建立出來的執行個體,其他兩類都是 beanName(避免過早執行個體化)

        // Separate between BeanPostProcessors that implement PriorityOrdered,
        // Ordered, and the rest.
        // 第 1 類: 實作了 PriorityOrdered 接口的
        List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
        // 實作了 `PriorityOrdered` 接口的 BeanPostProcessor 還有個細分的類型
        // 第 2 類: MergedBeanDefinitionPostProcessor 類型的 BeanPostProcessor
        List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
        // 第 3 類: 實作了 Ordered 接口的
        List<String> orderedPostProcessorNames = new ArrayList<>();
        // 第 4 類: 普通的 BeanPostProcessor
        List<String> nonOrderedPostProcessorNames = new ArrayList<>();
        for (String ppName : postProcessorNames) {
            // 第 1 類
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                // 這裡是通過 getBean 真真正正建立了 BeanPostProcessor 類型的 Bean
                // 而不是 beanName
                BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
                priorityOrderedPostProcessors.add(pp);
                // 第 2 類
                if (pp instanceof MergedBeanDefinitionPostProcessor) {
                    internalPostProcessors.add(pp);
                }
            }
            // 第 3 類
            else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
                orderedPostProcessorNames.add(ppName);
            }
            // 第 4 類
            else {
                nonOrderedPostProcessorNames.add(ppName);
            }
        }

        // 經過上面的循環,已經給各種 BeanPostProcessor 分好類了
        // 下面就是按照不同類型的優先級注冊到 BeanPostProcessor 中

        // 1. 先注冊實作了 `PriorityOrdered` 接口的 BeanPostProcessor
        // First, register the BeanPostProcessors that implement PriorityOrdered.
        sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
        // 其實就是調用了 beanFactory.addBeanPostProcessor 給目前 BeanFactory 中新增 BeanPostProcessor
        // 作用是: 将給定的 BeanPostProcessor 添加到最後
        registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

        // 2. 注冊實作了 `Ordered` 接口的 BeanPostProcessor
        // Next, register the BeanPostProcessors that implement Ordered.
        // 先通過 getBean 建立執行個體,然後注冊
        List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
        for (String ppName : orderedPostProcessorNames) {
            BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
            orderedPostProcessors.add(pp);
            if (pp instanceof MergedBeanDefinitionPostProcessor) {
                internalPostProcessors.add(pp);
            }
        }
        sortPostProcessors(orderedPostProcessors, beanFactory);
        registerBeanPostProcessors(beanFactory, orderedPostProcessors);

        // 3. 普通的 BeanPostProcessor
        // Now, register all regular BeanPostProcessors.
        // 先通過 getBean 建立執行個體,然後注冊
        List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
        for (String ppName : nonOrderedPostProcessorNames) {
            BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
            nonOrderedPostProcessors.add(pp);
            if (pp instanceof MergedBeanDefinitionPostProcessor) {
                internalPostProcessors.add(pp);
            }
        }
        registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

        // 4. 注冊 internalPostProcessors
        // 所謂的 `internalPostProcessors` 指的就是 `MergedBeanDefinitionPostProcessor` 這種子接口 
        // Finally, re-register all internal BeanPostProcessors.
        sortPostProcessors(internalPostProcessors, beanFactory);
        registerBeanPostProcessors(beanFactory, internalPostProcessors);

        // 5. 将 `ApplicationListenerDetector` 移動到最後
        // 就是來處理實作了 `ApplicationListener` 這種事件接口的 Bean 的
        // Re-register post-processor for detecting inner beans as ApplicationListeners,
        // moving it to the end of the processor chain (for picking up proxies etc).
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
    }
}           

BeanPostProcessorChecker

現在回頭再看看 BeanPostProcessorChecker。他是用來檢測:在 BeanPostProcessor 的初始化過程中是不是有其他普通的 Bean 被過早初始化了。

  • 什麼叫普通的 Bean: 除了 BeanPostProcessor 類型和 BeanDefinition.role == RootBeanDefinition.ROLE_INFRASTRUCTURE 的 Bean 都是普通 Bean
  • 什麼叫過早初始化: 一個普通 Bean 的正常建立流程應該經過一系列的 BeanPostProcessor 處理,但是現在 BeanPostProcessor 自己還在初始化過程中呢。這時候如果初始化一個普通的 Bean ,就無法保證這個普通 Bean 被所有的 BeanPostProcessor 處理,也就是說 Bean 被提前初始化了。

成員變量 beanPostProcessorTargetCount 什麼意思呢?

其實就是上面代碼中的 int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length; 這一行。

  • beanFactory.getBeanPostProcessorCount(): 指的是 BeanFactory 中已經存在的 BeanPostProcessor 執行個體的個數
  • +1: 指的是 BeanPostProcessorChecker 自己
  • postProcessorNames.length: 指的是經過上面的幾波循環之後新增了多少 BeanPostProcessor 的執行個體
private static final class BeanPostProcessorChecker implements BeanPostProcessor {

    private static final Log logger = LogFactory.getLog(BeanPostProcessorChecker.class);

    private final ConfigurableListableBeanFactory beanFactory;

    private final int beanPostProcessorTargetCount;

    public BeanPostProcessorChecker(ConfigurableListableBeanFactory beanFactory, int beanPostProcessorTargetCount) {
        this.beanFactory = beanFactory;
        this.beanPostProcessorTargetCount = beanPostProcessorTargetCount;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        // 除了 BeanPostProcessor 類型 和 BeanDefinition.role == `RootBeanDefinition.ROLE_INFRASTRUCTURE`
        if (!(bean instanceof BeanPostProcessor) && !isInfrastructureBean(beanName) &&
                // 這個小于判斷如果成立的話 就說明現在還有 `BeanPostProcessor` 沒有執行個體化完成
                this.beanFactory.getBeanPostProcessorCount() < this.beanPostProcessorTargetCount) {
            if (logger.isInfoEnabled()) {
                logger.info("Bean '" + beanName + "' of type [" + bean.getClass().getName() +
                        "] is not eligible for getting processed by all BeanPostProcessors " +
                        "(for example: not eligible for auto-proxying)");
            }
        }
        return bean;
    }

    private boolean isInfrastructureBean(@Nullable String beanName) {
        if (beanName != null && this.beanFactory.containsBeanDefinition(beanName)) {
            BeanDefinition bd = this.beanFactory.getBeanDefinition(beanName);
            return (bd.getRole() == RootBeanDefinition.ROLE_INFRASTRUCTURE);
        }
        return false;
    }
}           

小節

通過這一步,所有的 BeanPostProcessor 的執行個體已經被建立了。并且都被注冊到了 BeanFactory 中了。

但是需要注意的是,這裡僅僅是 BeanPostProcessor 自己的執行個體化和注冊,還沒到 BeanPostProcessor 執行的時候呢。

後續的 Bean 建立過程中,這些 BeanPostProcessor 就可以發揮作用了。

繼續閱讀