【精讀】你知道Spring中BeanFactoryPostProcessors是如何執行的嗎?

瞭解了BeanDefinition以及生命週期的大概概念以後,咱們班能夠試着看一下源碼!咱們上一章也說到,BeanFactoryPostProcessors的執行時機是:在掃描完成以後,實例化以前! 那麼咱們看一下Spring是如何去回調BeanFactoryPostProcessors的呢?java

org.springframework.context.support.AbstractApplicationContext#refresh
org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors
org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
    
invokeBeanFactoryPostProcessors就是掃描項目轉換成BeanDefinition 而後回調BeanFactoryPostProcessors的地方!咱們看源碼也是從這裏開始看!
複製代碼

我這裏會分段截取代碼進行講解,文章末尾會複製整段代碼:程序員

代碼一:初始化對應的集合

image-20200908091328833

進入到這個方法以後,spring

  1. 咱們會迎來第一個判斷,也就是判斷當前使用的工廠是否是BeanDefinitionRegistry,這個判斷99%都會返回爲true,爲何呢?由於除非進行了很深度的擴展Spring,本身繼承整個工廠的頂級接口AliasRegistry去實現一個徹底由本身實現的工廠,這個判斷纔會被跳過!這個對於咱們現階段來講,不用太過深究,咱們如今就先認定一件事,咱們使用的beanFactory工廠必定是 BeanDefinitionRegistry類型的,這個判斷也必定會進來;
  2. 初始化了二個集合,這二個集合各有用意,第一個集合就存放咱們手動提供給Spring的後置處理器,注意這個手動,他並非又Spring掃描獲得的,而是咱們本身設置進去的,固然這裏是後話!
  3. 第二個集合是存放執行過程當中找到的BeanDefinitionRegistryPostProcessor,爲何要存放他呢?由於他是BeanFactoryPostProcessor的子類,在整個執行調用過程當中,咱們會先執行BeanDefinitionRegistryPostProcessor類型的後置處理器,在執行BeanFactoryPostProcessor類型的,可是由於是子類和父類的關係,爲了不後面重複的獲取,就索性吧BeanDefinitionRegistryPostProcessor存儲起來,等待BeanDefinitionRegistryPostProcessor的方法執行完畢以後,就直接執行他父類的方法,這也可以從側面證實BeanDefinitionRegistryPostProcessorpostProcessBeanFactory方法是優先於BeanFactoryPostProcessorpostProcessBeanFactory方法先執行的!固然這一點我會在後面用代碼進行驗證!

代碼2、遍歷用戶本身手動添加的後置處理器

image-20200908092446476

這個循環是爲了循環程序員本身手動添加的後置處理器(不用太過深究,後面我會用代碼說明),若是是BeanDefinitionRegistryPostProcessor的就先調用了,若是是BeanFactoryPostProcessor類型的,就先放到regularPostProcessors集合中,等待BeanDefinitionRegistryPostProcessor執行完畢後,在進行BeanFactoryPostProcessor的調用!緩存

代碼三:開始調用實現了PriorityOrdered接口的BeanDefinitionRegistryPostProcessor

image-20200908093030287

咱們迎來了第一段比較重要的代碼,首先會先去在整個bean工廠尋找BeanDefinitionRegistryPostProcessor類型的而且實現了類PriorityOrdered的類!注意此時沒有任何人向beanFactory中放置該類型的類,他只有一個實現,就是Spring在開天闢地的時候初始化的幾個BeanDefinition,其中有一個符合條件markdown

image-20200908093912603

他就是ConfigurationClassPostProcessor,這個類是Spring初始化的時候就放置到容器裏面的,他作的事情很很簡單,就是解析Spring配置類,而後掃描項目,將項目內符合條件的類,好比@Server、@Bean之流加了註解的類,轉換成BeanDefinition,而後存放到容器,請注意一點,此時通過ConfigurationClassPostProcessor的執行以後,咱們Spring容器中有值了,有了咱們配置的全部的應該被Spring管理的類!此時再去尋找就會尋找咱們本身定義的一些後置處理器了!post

代碼四:開始調用實現了Ordered接口的BeanDefinitionRegistryPostProcessor

image-20200908094511381

這一段代碼基本和上面的代碼同樣,惟一不一樣的就是本次尋找的是實現了Ordered了的接口,由於上面ConfigurationClassPostProcessor的執行,此時容器內部就又了咱們本身定義的類信息,因此若是咱們有一個類實現了BeanDefinitionRegistryPostProcessor且實現了Ordered接口,那麼此時就可以被執行了!學習

代碼五:開始調用剩餘的BeanDefinitionRegistryPostProcessor

image-20200908101810906

通過上面兩個實現了PriorityOrderedOrdered接口兩種BeanDefinitionRegistryPostProcessor以後,優先級別最高的已經執行完畢了,後續只須要去執行剩餘的BeanDefinitionRegistryPostProcessor就能夠了,可是有些讀者可能會很疑惑,上面兩種調用的都是一個循環就完事了,可是爲何這裏須要一個死循環呢?spa

由於,BeanDefinitionRegistryPostProcessor是一個接口,在回調他的方法的時候,裏面的方法可能又註冊了一些BeanDefinition,這些BeanDefinition也是BeanDefinitionRegistryPostProcessor類型的,舉個例子就像俄羅斯套娃同樣,每個裏面都會進行一些註冊,誰也不知道會進行套多少層,故而要進行一個死循環,只要有,就一直遍歷尋找,直到執行完爲止!相似於下圖這樣:debug

image-20200908095928070

代碼六:開始調用BeanDefinitionRegistryPostProcessor的父類方法

image-20200908101909970

  • 第一行代碼的意思是執行BeanDefinitionRegistryPostProcessor的父類方法,也就是BeanFactoryPostProcessor的回到方法,由於BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor類型的,爲了不重複查詢就實現執行了,他的優先級高於普通的BeanFactoryPostProcessor!
  • 第二行代碼的意思是,執行用戶手動添加的BeanFactoryPostProcessor!後面說!

代碼七:開始尋找BeanFactoryPostProcessor

image-20200908103447903

這個代碼邏輯不難看懂code

  1. 先尋找全部的BeanFactoryPostProcessor
  2. 初始化三個集合,實現PriorityOrdered的集合、實現了Ordered的集合、剩餘的BeanFactoryPostProcessor集合
  3. 遍歷尋找到的全部的BeanFactoryPostProcessor
  4. 判斷當 processedBeans集合已經存在,也就是被BeanDefinitionRegistryPostProcessor處理過的直接跳過,避免重複執行!
  5. 若是是實現了PriorityOrdered接口,直接getBean()提早實例化後,加入到對應的集合,注意此時已經進行實例化!
  6. 若是是實現了Ordered接口,那麼吧他的名字放到對應的集合中,注意此時他沒有實例化!
  7. 將普通的BeanFactoryPostProcessor放到對應的集合,注意也沒有實例化!

經過上述,咱們知道了一件事,只有PriorityOrdered類型的BeanFactoryPostProcessor被實例化了,而後放置到了集合中去!

代碼八:開始執行BeanFactoryPostProcessor

image-20200908102912853

  • 咱們先對實現了PriorityOrdered的集合進行排序後執行,注意,由於上面在添加到集合的時候已經經過igetBean()實例化了,因此,此時能夠直接執行!
  • 遍歷實現了Ordered的beanName集合,而後經過getBean,實例化對應的BeanFactoryPostProcessor,放到對應的集合orderedPostProcessors,排序後進行執行!
  • 遍歷剩餘的BeanFactoryPostProcessor,而後getBean實例化後,直接執行!

代碼流程圖

4576

完整的代碼:

/** * 掃描項目 * 調用BeanDefinitionRegistryPostProcessor 將對應的類轉成BeanDefinition * 調用 BeanFactoryPostProcessors的回調方法 * @param beanFactory bean工廠 * @param beanFactoryPostProcessors 手動提供的後置處理器 */
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

    // 若是有的話,首先調用BeanDefinitionRegistryPostProcessors。
    Set<String> processedBeans = new HashSet<>();
    //默認使用的是DefaultListableBeanFactory工廠對象 因此i這個判斷必定會進入進來
    if (beanFactory instanceof BeanDefinitionRegistry) {
        //事實上就是Bean工廠
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
        //存放程序員本身手動提供給Spring的後置處理器
        List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
        //存放執行該過程當中尋找到的 BeanDefinitionRegistryPostProcessor
        List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

        //循環遍歷bean工廠後處理器 可是這個的debug的對象確實爲Null不知道爲何 事實上它並不會進入到這裏
        //這個是掃描用戶本身手動添加的一些BeanFactoryPostProcessors
        //事實上 咱們不多會對這裏進行更改,只有在對接或者開發第三方組件的時候可能會手動的設置一個後置處理器
        //正常狀況下極少可以使用到這種狀況
        for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
            //這個判斷就是爲了保證spring本身的掃描處理器先執行 由於此時spring尚未完成掃描
            if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor;
                registryProcessor.postProcessBeanDefinitionRegistry(registry);
                registryProcessors.add(registryProcessor);
            }
            else {
                //本身定義的內助處理器
                regularPostProcessors.add(postProcessor);
            }
        }

        // 不要在這裏初始化FactoryBeans:咱們須要保留全部常規bean
        // 未初始化,讓Bean工廠後處理器對其應用!
        // 在實現的BeanDefinitionRegistryPostProcessor之間分開
        // PriorityOrdered,Ordered和其餘。
        List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

        // 首先,調用實現PriorityOrdered(排序接口)的BeanDefinitionRegistryPostProcessors。 這是獲取內置bean工廠後置處理器的beanName
        //查出全部實現了BeanDefinitionRegistryPostProcessor接口的bean名稱
        //調用了一次BeanDefinitionRegistryPostProcessor子類 PriorityOrdered
        //獲取 BeanDefinitionRegistryPostProcessor 的子類 事實上 這裏只有一個叫作 ConfigurationClassPostProcessor 他實現了 PriorityOrdered接口
        //BeanFactoryPostProcessor 也就是 ConfigurationClassPostProcessor 會被添加到容器裏面
        String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        for (String ppName : postProcessorNames) {
            //判斷當前這個類是否是實現了PriorityOrdered接口
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                //getBean會提早走生命週期
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                //將這個已經處理過的添加到集合裏面
                //爲何要天機哀悼集合裏面呢?由於自己他就屬於 BeanDefinitionRegistryPostProcessor 是 BeanFactoryPostProcessor的子類
                //那麼確定 在執行BeanFactoryPostProcessor的回調的時候,他還會再次的被獲取執行
                //索性 Spring爲了節省效率,避免這部分 BeanDefinitionRegistryPostProcessor類被重複 獲取,就在徹底調用了BeanDefinitionRegistryPostProcessor類以後
                //將這一部分的接口直接給執行了也就是BeanDefinitionRegistryPostProcessor的BeanFactoryPostProcessor的回調方法是優先於直接實現BeanFactoryPostProcessor方法的
                //既然在執行BeanFactoryPostProcessor以前就執行了對應的方法回調,那麼確定,執行BeanFactoryPostProcessor的時候要把以前已經執行過的過濾掉
                //故而會將BeanDefinitionRegistryPostProcessor存儲起來,後續執行BeanFactoryPostProcessor會跳過集合裏面的類
                processedBeans.add(ppName);
            }
        }
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        //見該處理器添加到對應的已註冊集合裏面 方面後面直接回調他們的父類方法也就是 BeanFactoryPostProcessors方法
        registryProcessors.addAll(currentRegistryProcessors);
        //調用Bean定義註冊表後處理器 這裏是真正的讀取類的bd的一個方法 ConfigurationClassPostProcessor 第一次調用beanFactory 後置處理器
        //這裏調用ConfigurationClassPostProcessor後置處理器會註冊一個後置處理器,下面進行回調
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        //清空當前這個處理器
        currentRegistryProcessors.clear();

        // 接下來,調用實現Ordered的BeanDefinitionRegistryPostProcessors。 Ordered
        postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        for (String ppName : postProcessorNames) {
            //判斷當前這個類是否是實現了Ordered接口
            if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                //getBean會提早走生命週期
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                processedBeans.add(ppName);
            }
        }
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        //見該處理器添加到對應的已註冊集合裏面 方面後面直接回調他們的父類方法也就是 BeanFactoryPostProcessors方法
        registryProcessors.addAll(currentRegistryProcessors);
        //調用當前的BeanDefinitionRegistryPostProcessor 回調方法
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        //清空當前這個處理器
        currentRegistryProcessors.clear();

        // 最後,調用全部其餘BeanDefinitionRegistryPostProcessor,直到沒有其餘的出現。
        boolean reiterate = true;
        //這裏爲何是死循環呢?
        //由於 BeanDefinitionRegistryPostProcessor 自己進行回調的時候會手動註冊一些特殊的類,例如再次註冊一個BeanDefinitionRegistryPostProcessor
        //類,可能手動註冊的類裏面還有,像套娃同樣,故而須要進行不斷的循環迭代獲取,從而達到遍歷所有的 BeanDefinitionRegistryPostProcessor的目的
        while (reiterate) {
            reiterate = false;
            //獲取全部的BeanDefinitionRegistryPostProcessor接口的實現類
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            //遍歷這些BeanDefinitionRegistryPostProcessor類
            for (String ppName : postProcessorNames) {
                //若是它不存在與這個集合裏面,證實沒有被上面處理過,就不會被跳過,這裏主要是解決重複執行的狀況
                if (!processedBeans.contains(ppName)) {
                    //添加到對應的當前處理器集合裏面
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    //添加到已處理集合裏面
                    processedBeans.add(ppName);
                    //將掃描標識爲true 準備下次執行
                    reiterate = true;
                }
            }
            //排序
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            //註冊到註冊集合裏面,便於後修直接回調父類
            registryProcessors.addAll(currentRegistryProcessors);
            //開始執行這些方法
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            //清空本次執行的處理集合
            currentRegistryProcessors.clear();
        }

        // 如今,調用到目前爲止已處理的全部處理器的postProcessBeanFactory回調。
        //BeanDefinitionRegistryPostProcessor 是 BeanFactoryPostProcessor
        //目的就是爲了不重複獲取
        invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
        //常規的 普通的工廠後置處理器
        //程序員手動提供給Spring的BeanFactory beanFactory.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor())
        invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
    } else {
        // 調用在上下文實例中註冊的工廠處理器。
        invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
    }

    // 不要在這裏初始化FactoryBeans:咱們須要保留全部常規bean
    // 未初始化,讓Bean工廠後處理器對其應用!
    //這裏是真正獲取容器內部全部的beanFactory的後置處理器
    String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

    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
        }
        //添加 實現了PriorityOrdered的BeanFactoryPostProcessors
        else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
        }
        //添加 實現了Ordered的BeanFactoryPostProcessors
        else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
            orderedPostProcessorNames.add(ppName);
        }
        else {
            //添加剩餘的
            nonOrderedPostProcessorNames.add(ppName);
        }
    }

    // 首先,調用實現PriorityOrdered的BeanFactoryPostProcessors。
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    //首先回調實現了PriorityOrdered的BeanFactoryPostProcessors
    invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

    // 接下來,調用實現Ordered的BeanFactoryPostProcessors。
    List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
    for (String postProcessorName : orderedPostProcessorNames) {
        //getBean能夠進行提早實例化進入生命週期
        orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    sortPostProcessors(orderedPostProcessors, beanFactory);
    // 接下來,調用實現Ordered的BeanFactoryPostProcessors。
    invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

    //最後,調用全部其餘BeanFactoryPostProcessors。
    List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
    for (String postProcessorName : nonOrderedPostProcessorNames) {
        //getBean能夠進行提早實例化進入生命週期
        nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    //這裏執行的自定義的bean工廠的後置處理器
    invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

    // 清除緩存的合併bean定義,由於後處理器可能具備修改了原始元數據,例如替換值中的佔位符...
    beanFactory.clearMetadataCache();
}
複製代碼

才疏學淺,若是文章中理解有誤,歡迎大佬們私聊指正!歡迎關注做者的公衆號,一塊兒進步,一塊兒學習! 歡迎關注做者

相關文章
相關標籤/搜索