悶棍暴打面試官 Spring源碼系列:(一) Spring 如何解決循環依賴

前言

初夏時節, 時間: AM 7.30分左右, 空無一人的健身房裡,一個碩大的身體在跑步機上扭動著, 不一會頭上便揮汗如雨, 他嘴上還不時嘀咕著

"循環依賴,單例模式,Bean的定位加載註冊,原型模式...", 漸漸跑著跑著就變成了慢慢悠悠的走走歇歇,忽然間感覺肩膀好像被磚頭砸了一下,

身後傳來一句 "你張大胖減肥是不可能減肥的,就是在健身房裡劃劃水才能維持的了生活 !" ,

大胖被拍的渾身一驚, 看了眼一身運動裝的 Mason, 急忙反駁道 "沒有調查就沒有發言權, 俺只是暫時休息下, 今天都已經跑了好幾個小時了呢,倒是 Mason 你像是來假健身的...",

Mason 笑笑說 "哎呀呀, 你這麼厲害呢,可惟獨肚子上的贅肉騙不了人啊,最近面試的怎麼樣?"

大胖 一臉愁容的說道: "最近招聘市場很給力,我也參加了不少面試,就是每次聊到 Spring 時被面試官三連追問 Spring是如何解決循環依賴, 而我對著個問題查了很多資料,但也就能回答個一知半解,然後就叫我回去等通知了..."

Mason 在跑步機上邊跑邊說 "Spring 解決循環依賴的這個場景, 其實也可以映射到生活中, 比如 你工作日睡過了又害怕遲到扣錢,就在 DD出行 App上選擇一個起始地打車, 同一時間來了兩輛 DD專車, 你也沒有check車牌就上車了, 司機也沒check你拉上就走,你一上車就聚精會神看起宅舞視頻, 結果到達別人的目的地發現上錯車,既遲到了又要付來回路費,那麼問題來了 你為什麼會上錯車呢? "

大胖 撓撓頭回答道: "因為睡過了怕遲到啊! 呸,不對, 因為要早起去打工!"

Mason 白了張大胖一眼說: "起不來是因為你天天熬夜,坐錯車是因為兩個原因: 1.沒有check車牌 2.DD專車不止一輛"

大胖 一臉懵X 的問道 "繞了半天, 那這上錯車和Spring創建Bean時的循環依賴又有什麼關係呢 ?"

Mason 一臉這孩子沒救了的表情回答道 "循環依賴的觸發條件就是, 你上了別人的DD專車, 而你打DD專車, 判斷是否循環依賴就需要 check車牌,如果要徹底根治循環依賴就必須讓世界上的 DD專車 只有一輛. Spring 中的循環依賴也是同理!"

悶棍暴打面試官 Spring源碼系列:(一) Spring 如何解決循環依賴

見微知著

我們暫不討論 Spring 的循環依賴, 先看一道 LeetCode 題目 141. 環形鏈表 擴展: 在多線程環境下使用JDK1.7中的HashMap, 併發調用resize()時會出現環形鏈表,後再get()會導致CPU 100%, 那我們該如何去判斷環形鏈表呢?

給定一個鏈表,判斷鏈表中是否有環。

為了表示給定鏈表中的環,我們使用整數 pos 來表示鏈表尾連接到鏈表中的位置(索引從 0 開始)。 如果 pos 是 -1,則在該鏈表中沒有環。

示例 1:

<code>輸入:head = [3,2,0,-4], pos = 1
輸出:true
解釋:鏈表中有一個環,其尾部連接到第二個節點。/<code>
悶棍暴打面試官 Spring源碼系列:(一) Spring 如何解決循環依賴

示例 2:

<code>輸入:head = [1,2], pos = 0
輸出:true
解釋:鏈表中有一個環,其尾部連接到第一個節點。/<code>
悶棍暴打面試官 Spring源碼系列:(一) Spring 如何解決循環依賴

示例 3:

<code>輸入:head = [1], pos = -1
輸出:false
解釋:鏈表中沒有環。/<code>
悶棍暴打面試官 Spring源碼系列:(一) Spring 如何解決循環依賴

那麼 Spring 中是用那種方式發現 循環依賴的呢 ? (文章結尾揭曉答案)

<code>//  Definition for singly-linked list.
public class ListNode {
    public int val;
    public ListNode next;
    public ListNode(int x) {
        val = x;
    }
}/<code>

Set判重

<code>  public boolean hasCycle_Set(ListNode head) {

        // 如果入參鏈表過短則不存在環
        if (head == null || head.next == null) {
            return false;
        }

        HashSet set = new HashSet<>();

        // 如果 遍歷到最後任然沒有發現環則不存在環
        while (head.next != null){

            // 將每一個遍歷過的元素存入,之後判重
            if (set.contains(head)){
                return true;
            }

            set.add(head);
            head = head.next;
        }

        return false;
    }/<code>
悶棍暴打面試官 Spring源碼系列:(一) Spring 如何解決循環依賴

快慢指針判重

<code> public boolean hasCycle_QuickSlowPointer (ListNode head) {

        // 如果入參鏈表過短則不存在環
        if (head == null || head.next == null) {
            return false;
        }
        ListNode slow = head;
        ListNode fast = head;

        // 如果 快指針遍歷到最後仍然沒有發現環則不存在環
        while (fast.next != null && fast.next.next != null){
            slow = slow.next;
            fast = fast.next.next;

            // 快指針每輪走兩步 慢指針每輪走一步 如果有環快慢指針最終就會相遇
            if (slow == fast){
                return true;
            }
        }
        return false;
    }/<code>
悶棍暴打面試官 Spring源碼系列:(一) Spring 如何解決循環依賴

新整了個活, 今後長期維護的一個LeetCode題解庫,歡迎 Star

LeetCode 漸進式題解庫: 讓天下沒有難刷的題 (Java)

悶棍暴打面試官 Spring源碼系列:(一) Spring 如何解決循環依賴

Spring 中常用的兩種 Bean DI 方式的循環依賴示例

Spring DI (Dependency Injection 依賴注入) 是指 Bean 被動接受其他 Bean的依賴注入而不自己主動去找, 簡而言之 Bean 不會從容器中查找它依賴的 Bean , 而是靠容器實例化 Bean 時由容器將它依賴的 Bean 注入, 此舉與Java 類實例化流程相反.

構造器 DI 示例代碼(基於Spring 5.1.6)

<code>package org.springframework.context.annotationX.circular.constructor;

import org.springframework.stereotype.Component;

/**
 * Spring Constructor DI 循環依賴  Bean1 Demo
 */
@Component
public class Bean1ConstructorBean2Demo {

   private Bean2ConstructorBean1Demo bean2;

    public Bean1ConstructorBean2Demo(Bean2ConstructorBean1Demo bean2DependBean1Demo) {
        this.bean2 = bean2DependBean1Demo;
    }

    public void hello() {
        bean2.hello();
    }
}
/<code>
<code>package org.springframework.context.annotationX.circular.constructor;

import org.springframework.stereotype.Component;

/**
 * Spring Constructor DI  循環依賴  Bean2 Demo
 */
@Component
public class Bean2ConstructorBean1Demo {

    private Bean1ConstructorBean2Demo bean1;

    public Bean2ConstructorBean1Demo(Bean1ConstructorBean2Demo bean1DependBean2Demo1) {
        bean1 = bean1DependBean2Demo1;
    }

    public void hello() {
        System.out.println("Run Circular Dependency Success");
    }
}
/<code>

註解自動裝配 DI 示例代碼

<code>package org.springframework.context.annotationX.circular.autowired;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * Spring  @Autowired DI 循環依賴  Bean1 Demo
 */
@Component
public class Bean1AutowiredBean2Demo {

   @Autowired
   private Bean2AutowiredBean1Demo bean2;

    public void hello() {
        bean2.hello();
    }
}/<code>
<code>package org.springframework.context.annotationX.circular.autowired;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * Spring  @Autowired DI  循環依賴  Bean2 Demo
 */
@Component
public class Bean2AutowiredBean1Demo {

    @Autowired
   private Bean1AutowiredBean2Demo bean1;

    public void hello(){
        System.out.println("Run Circular Dependency Success");
    }
}/<code>

兩種 DI 方式的單元測試代碼

<code>package org.springframework.context;


import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotationX.circular.autowired.Bean1AutowiredBean2Demo;
import org.springframework.context.annotationX.circular.constructor.Bean1ConstructorBean2Demo;

/**
 * Created by 以鬥爭求團結則團結存,以退讓求團結則團結亡 !
 */
public class AnnotationCircularDependencyTestX {

    @Test
    public void diBeanByAutowired() throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.scan("org.springframework.context.annotationX.circular.autowired");
        context.refresh();
        Bean1AutowiredBean2Demo bean1 = (Bean1AutowiredBean2Demo) context.getBean("bean1AutowiredBean2Demo");
        bean1.hello();
    }

    @Test
    public void diBeanByConstructor () throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.scan("org.springframework.context.annotationX.circular.constructor");
        context.refresh();
        Bean1ConstructorBean2Demo bean1 = (Bean1ConstructorBean2Demo) context.getBean("bean1ConstructorBean2Demo");
        bean1.hello();
    }
}/<code>

猜猜上面那種 DI 方式打印了 "Run Circular Dependency Success" 以及它解決循環依賴的方式 ?

悶棍暴打面試官 Spring源碼系列:(一) Spring 如何解決循環依賴

答案: 註解自動裝配 DI 示例代碼 打印成功 而 構造器 DI 示例代碼因為循環依賴運行失敗 , 那這兩種方式有什麼區別呢 !

(構造器 DI 錯誤日誌)

<code> Unsatisfied dependency expressed through constructor parameter 0; nested exception is
 org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name
 'bean2ConstructorBean1Demo' defined in file
 [D:\SpringFamily-SourceCodeStudy\Spring-Framework\spring-framework-5.1.6.REL
 EASE\spring-context\out\test\classes\org\springframework\context\annotationX\circular\constructor\Bean2Const
 ructorBean1Demo.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is
 org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name
 'bean1ConstructorBean2Demo': Requested bean is currently in creation: Is there an unresolvable circular
 reference?

 at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:769)
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1341)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:849)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877)
    ..../<code>
  • 註解自動裝配 DI 方式 優點: 基於三層緩存不會發生循環依賴 自描述清晰 缺點: 對構建單元測試不友好
  • 構造器 DI 方式 優點: 代碼結構明確,可讀性高 構建單元測試友好 非IOC容器環境可使用new實例化該類的對象。 缺點: 會發生循環依賴 當注入參數較多時,代碼臃腫。

對於循環依賴問題,Spring根據注入方式,採取不同的處理策略,如果依賴雙方都是使用屬性值注入或者Setter方法注入,則Spring可以自動解決循環依賴注入問題,Spring 程序可以成功啟動;如果依賴雙方是使用構造函數注入對方或者主Bean對象使用構造函數注入或循環注入的Bean都是原型模式

,則Spring 無法解決循環依賴注入 ,Spring程序報循環依賴無法啟動。

註解 DI 方式 的運行成功原因

註解 DI 方式與 構造器 DI 方式 最終要達到的目的相同, 但Spring 對它倆的實現卻不太一樣, Spring-Context 在 AbstractApplicationContext.refresh() 方法完成 Bean 的關鍵生命週期 IOC, 實例化, DI 等, DI 具體是 IOC 完成後調用 finishBeanFactoryInitialization() 方法, 具體方法邏輯如下

  • 能觸發依賴注入的條件有倆: 1. 第一次調用 getBean 方法時, 2. 懶加載被預實例化時, 此方法滿足了其中第一條.
  • 1.根據 beanDefinitionMap 依次判斷 Bean 是否 Lazy, 是否 Prototype, 是否 Abstract 等等
  • 2.接下來根據判斷結果 填充構造方法來反射 Bean 的從而實例化. 所以在此之前必須推斷Bean的構造方法.
  • 3.反射實例化一個對象;注意我這裡說的是對象、對象、對象;不是並不是一個完整的bean,因為 對象屬性是沒有注入,所以不是一個完整的bean;
  • 4.Spring 處理 合併後的 BeanDefinition.
  • 5.判斷是否支持 循環依賴 如果支持則提前把 一個工廠存入 singletonFactories Map>
  • 6.進行屬性注入
  • 7.回調 Aware 接口, 生命週期回調方法, 是否需要代理
  • 8.put 到 Spring容器
  • 文章最後會帶大家詳細閱讀上述源碼.
悶棍暴打面試官 Spring源碼系列:(一) Spring 如何解決循環依賴

成功原因:

<code>// 是否需要提前曝光,用來解決循環依賴時使用
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
        isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
    if (logger.isTraceEnabled()) {
        logger.trace("Eagerly caching bean '" + beanName +
                "' to allow for resolving potential circular references");
    }
    // 這裡是一個匿名內部類, 為了循環引用, 儘早持有對象的引用    
    // 解決循環依賴 第二個參數是回調接口,實現的功能是將切面動態織入 bean
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

protected void addSingletonFactory(String beanName, ObjectFactory> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
        synchronized (this.singletonObjects) {
            // 判斷 singletonObjects 不存在 beanName
            if (!this.singletonObjects.containsKey(beanName)) {
            // 註釋 5.4 放入 beanName -> beanFactory,到時在 getSingleton() 獲取單例時,可直接獲取創建對應 bean 的工廠,解決循環依賴
            this.singletonFactories.put(beanName, singletonFactory);
            // 從提前曝光的緩存中移除,之前在 getSingleton() 放入的
            this.earlySingletonObjects.remove(beanName);
            // 往註冊緩存中添加 beanName
            this.registeredSingletons.add(beanName);
        }
    }
}
/<code> 

先來看 earlySingletonExposure 這個變量: 從字面意思理解就是需要提前曝光的單例

有以下三個判斷條件:

  • mbd 是否是單例
  • 該容器是否允許循環依賴
  • 判斷該 bean 是否在創建中。

如果這三個條件都滿足的話,就會執行 addSingletonFactory 操作。要想著,寫的代碼都有用處,所以接下來看下這個操作解決的什麼問題和在哪裡使用到吧

悶棍暴打面試官 Spring源碼系列:(一) Spring 如何解決循環依賴

A 類中含有屬性 B,B 類中含有屬性 A,這兩個類在初始化的時候經歷了以下的步驟:

  1. 創建 Bean1AutowiredBean2Demo,先記錄對應的 beanName 然後將 Bean1AutowiredBean2Demo的創建工廠 beanFactoryA 放入緩存中
  2. 對 Bean1AutowiredBean2Demo的屬性填充方法 populateBean,檢查到依賴 Bean2AutowiredBean1Demo,緩存中沒有 Bean2AutowiredBean1Demo 的實例或者單例緩存,於是要去實例化 Bean2AutowiredBean1Demo。
  3. 開始實例化 Bean2AutowiredBean1Demo,經歷創建 Bean1AutowiredBean2Demo的過程,到了屬性填充方法,檢查到依賴了 Bean1AutowiredBean2Demo。
  4. 調用 getBean(Bean1AutowiredBean2Demo) 方法,在這個函數中,不是真正去實例化 Bean1AutowiredBean2Demo,而是先去檢測緩存中是否有已經創建好的對應的 bean,或者已經創建好的 beanFactory
  5. 檢測到 beanFactoryA 已經創建好了,而是直接調用 ObjectFactory 去創建 Bean1AutowiredBean2Demo
悶棍暴打面試官 Spring源碼系列:(一) Spring 如何解決循環依賴

構造器 DI 方式 運行失敗的原因

構造方法DI 拋出異常前調用堆棧信息

悶棍暴打面試官 Spring源碼系列:(一) Spring 如何解決循環依賴

失敗原因: 根據上述堆棧可以分析, autowireConstructor() 試圖通過構造方法反射 bean1ConstructorBean2Demo 實例時它必須先實例化 bean2ConstructorBean1Demo 然後依次循環, 走到 getSingleton() -> DefaultSingletonBeanRegistry.beforeSingletonCreation() 方法時就檢測出異常, 那麼為什麼這種方式沒有像 註解 DI 那樣解決問題呢 ?

  • 註解DI方式 與 構造器DI方式最大的區別在與 AbstractAutowireCapableBeanFactory.createBeanInstance() 中的實例化策略不太一樣. 從各自定義SpringBean的源代碼上看, 構造器DI方式 需要申明當前類的構造器以及依賴的類, 而 註解DI方式則不需要 (默認空參)
  • 構造器DI: return autowireConstructor(beanName, mbd, ctors, args); 使用容器的自動裝配特性, 調用匹配的構造方法進行實例化
  • 註解DI: return instantiateBean(beanName, mbd); 使用默認的無參構造方法進行實例化
  • 如上圖所示, 調用堆棧 在 createBeanInstance() 實例化方法中發生了循環引用, 並沒有執行到 populateBean()進行依賴注入. 為什麼會發生這一切?

在此之前建議閱讀一下 Spring官方對循環依賴的文檔

悶棍暴打面試官 Spring源碼系列:(一) Spring 如何解決循環依賴

DI時 thorw BeanCurrentlyInCreationException 代碼片段

<code>// 構造方法DI getSingleton() 中 thorw BeanCurrentlyInCreationException
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    // 當前 Bean 不存在可排除的 inCreationCheckExclusions && 當前 Bean 之前已存在於 則 thorw singletonsCurrentlyInCreation 中
    protected void beforeSingletonCreation(String beanName) {
        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }
    }

    protected void afterSingletonCreation(String beanName) {
        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
            throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
        }
    }
}
/<code>

構造方法DI thorw 的觸發原因: 兩次 beforeSingletonCreation() 同一個Bean, 因為如果是沒有發生循環依賴的話接下來會執行 afterSingletonCreation(beanName) 清除本輪 singletonsCurrentlyInCreation.remove(beanName) 但在 beforeSingletonCreation--> 遞歸 autowireConstructor()

悶棍暴打面試官 Spring源碼系列:(一) Spring 如何解決循環依賴

<code>// 原型BeanDI doGetBean 中 thorw BeanCurrentlyInCreationException
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
        implements AutowireCapableBeanFactory {

    protected  T doGetBean(final String name, @Nullable final Class requiredType,
        @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

      // 如果之前創建過相同的原型Bean 則 thorw
        if (isPrototypeCurrentlyInCreation(beanName)) {
          throw new BeanCurrentlyInCreationException(beanName);
        }

        /** 創建原型模式 Bean 的實例對象*/
         if (mbd.isPrototype()) {
            // 原型模式 (Prototype) 每次都會創建一個新的對象
            Object prototypeInstance = null;
        try {
            // 回調 beforePrototypeCreation() 方法, 默認的功能是註冊當前創建的原型對象
            beforePrototypeCreation(beanName);
            // 創建指定 Bean 的對象實例
            prototypeInstance = createBean(beanName, mbd, args);
         }
            finally {
            // 回調 afterPrototypeCreation() 方法, 默認的功能是告訴 IOC 容器 不再創建指定 Bean 的原型對象
            afterPrototypeCreation(beanName);
                           }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
         }
        ...
    }
} 

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
    private final ThreadLocal prototypesCurrentlyInCreation =
            new NamedThreadLocal 
<>("Prototype beans currently in creation"); protected boolean isPrototypeCurrentlyInCreation(String beanName) { Object curVal = this.prototypesCurrentlyInCreation.get(); return (curVal != null && (curVal.equals(beanName) || (curVal instanceof Set && ((Set>) curVal).contains(beanName)))); } protected void beforePrototypeCreation(String beanName) { Object curVal = this.prototypesCurrentlyInCreation.get(); if (curVal == null) { this.prototypesCurrentlyInCreation.set(beanName); } else if (curVal instanceof String) { Set beanNameSet = new HashSet<>(2); beanNameSet.add((String) curVal); beanNameSet.add(beanName); this.prototypesCurrentlyInCreation.set(beanNameSet); } else { Set beanNameSet = (Set) curVal; beanNameSet.add(beanName); } } protected void afterPrototypeCreation(String beanName) { Object curVal = this.prototypesCurrentlyInCreation.get(); if (curVal instanceof String) { this.prototypesCurrentlyInCreation.remove(); } else if (curVal instanceof Set) { Set beanNameSet = (Set) curVal; beanNameSet.remove(beanName); if (beanNameSet.isEmpty()) { this.prototypesCurrentlyInCreation.remove(); } } } }/<code>

原型BeanDI thorw 的觸發原因: 兩次 beforePrototypeCreation() 同一個Bean, 因為如果是沒有發生循環依賴的話接下來會執行 afterPrototypeCreation(beanName) 清除本輪 prototypesCurrentlyInCreation.remove() 但在 beforePrototypeCreation--> 遞歸 doGetBean()

回溯幾個有意思的問題

Spring是如何發現循環依賴的?

巧妙的用了LeetCode[141]中 Set 解法 把Bean 的加載順序當作一個單向鏈表邊存入邊判重.

Spring的註解DI方式 是如何解決循環依賴的 ?

因為使用 註解DI 代碼風格上是沒有構造函數的, 在AbstractAutowireCapableBeanFactory.createBeanInstance() 走空參構造進行實例化, 所以不需要去像構造器DI 那樣去實例化別的類, 然後在 populateBean() 中進行屬性注入, 這時候已經完成實例化了要進行依賴注入了, 構造器DI方式就是在 實例化的時候翻車的呀, 具體怎麼進行循環依賴的屬性注入就靠 二 三級緩存咯.

  • 一級緩存: singletonObjects 它是我們最熟悉的朋友,俗稱“單例池”“容器”,緩存創建完成單例Bean的地方, 也可以稱之為 Spring 容器.
  • 二級緩存: singletonFactories 映射創建Bean的原始工廠
  • 三級緩存: earlySingletonObjects 映射Bean的早期引用,也就是說在這個Map裡的Bean不是完整的,甚至還不能稱之為“Bean”,只是一個Instance.

千言萬語都在gif圖裡, 感謝作者vt 授權...

悶棍暴打面試官 Spring源碼系列:(一) Spring 如何解決循環依賴

修復構造器 DI 引發的循環依賴的補丁有那幾種 ?

  • 在主構造DI 方法上加上 @Lazy, Spring會動態代理創建代理類來解決
  • 在發生循環依賴的注入主類上加上 @Autowired, 並記得刪除構造函數
  • 實現 InitializingBean, ApplicationContextAware 接口, 在Spring 用 InitializingBean 時手動獲取容器注入.
  • 更多

Spring Bean 是如何被創建的 ?

在學習 Spring 時你可以把它比作一家 糖果工廠 , 糖果工廠裡很多條夾心軟糖生產線, 其中最賺錢的兩條夾心軟糖生產線, 分別是A生產線 與X生產線, A生產線生產軟糖要必備一種叫@註解的糖漿原料, X 生產線則要必備另一種叫

兩種軟糖的初體驗

<code>import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SoftSweetsTest {

    @Test
    public void A_ProductLine() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.scan("org.springframework.context.softsweetsX");
        context.refresh();
        SoftSweetsBean bean = (SoftSweetsBean) context.getBean("softSweetsBean");
        System.out.println("\n新鮮出爐的A軟糖 ~~~ \n 生產線名稱: " + bean.getProductionLineName() + "\n 生產日期: " + bean.getDateManufacture());
    }

    @Test
    public void X_ProductLine() {
        // test-resources
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("org/springframework/beans/factory/xml/SoftSweetsX.xml");
        SoftSweetsBean bean = (SoftSweetsBean) context.getBean("softSweetsBean");
        System.out.println("\n新鮮出爐的X軟糖 ~~~ \n 生產線名稱: " + bean.getProductionLineName() + "\n 生產日期: " + bean.getDateManufacture());
    }
}/<code>

控制檯輸出結果

<code>新鮮出爐的X軟糖 ~~~ 
 生產線名稱: org.springframework.context.support.ClassPathXmlApplicationContext@525b461a
 生產日期: 2020-05-28T13:57:23.738+08:00[Asia/Shanghai]

新鮮出爐的A軟糖 ~~~ 
 生產線名稱: org.springframework.context.annotation.AnnotationConfigApplicationContext@10db82ae
 生產日期: 2020-05-28T13:57:24.784+08:00[Asia/Shanghai]/<code> 

如果你對生產軟糖感興趣 來吧 -> SpringFamily-SourceCodeStudy

Bean 加載步驟

  • IOC (Inversion of Control 控制反轉) 定位 (確定原料位置) 加載 (找到原料後提取為可註冊 BeanDefinition) 註冊 (將 BeanDefinition 校驗後註冊到 Map beanDefinitionMap)
  • DI (Dependency Injection 依賴注入) 實例化 (反射 new 對象)ioc 依賴注入 (容器主動查找 bean 依賴)

IOC 控制反轉

悶棍暴打面試官 Spring源碼系列:(一) Spring 如何解決循環依賴

兩條生產線的 定位與 加載 代碼

<code>// X 生產線
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {

    public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[] {configLocation}, true, null);
    }

    public ClassPathXmlApplicationContext(
                String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
                throws BeansException {
            // 設置容器資源加載器
            super(parent);
            /*   將配置的Bean信息為 Spring 封裝的 Resource */
            setConfigLocations(configLocations);
            if (refresh) {
                refresh();
            }
        }

public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {

    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // 創建 XmlBeanDefinitionReader, 即創建 Bean 讀取器
        //  並通過回調設置到容器中, 容器使用該讀取器讀取 Bean 配置資源
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // 為 Bean 讀取器設置 Spring 資源加載器
        // AbstractXmlApplicationContext 的祖先父類 AbstractApplicationContext 繼承 DefaultResourceLoader
        // 因此容器本身也是一個資源加載器
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        // 為Bean 讀取器設置 SAX xml 解析器
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // 當Bean 讀取器讀取 Bean 定義 xml 資源文件時, 啟用 xml 的校驗機制
        initBeanDefinitionReader(beanDefinitionReader);
        // Bean 讀取器真正實現加載的方法
        loadBeanDefinitions(beanDefinitionReader);
    }
}

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

            // 按照 Spring 的Bean 語義要求將 Bean 配置信息解析並轉換為容器內部數據結構
        public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
            /* 得到 BeanDefinitionDocumentReader 來對 XML 格式的 BeanDefinition 進行解析*/
            BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
            // 獲得容器中註冊的 Bean 總數 (包含內置 bean)
            int countBefore = getRegistry().getBeanDefinitionCount();
            // 解析過程的入口, 這裡使用了委派模式, BeanDefinitionDocumentReader 只是一個接口
            /*  具體的解析過程由實現類 DefaultBeanDefinitionDocumentReader 完成 */
            documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
            // 統計解析的 Bean 數量
            return getRegistry().getBeanDefinitionCount() - countBefore;
        }
    }
}

// ----------------------------------------------- 分割線 ---------------------------------------------------

// A 生產線
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
    public void scan(String... basePackages) {
            Assert.notEmpty(basePackages, "At least one base package must be specified");
            /*  */
            this.scanner.scan(basePackages);
    }
}

public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {

    public int scan(String... basePackages) {
        // 獲得容器中註冊的 Bean 總數 (包含內置 bean)
        int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

        doScan(basePackages);

        // Register annotation config processors, if necessary.
        if (this.includeAnnotationConfig) {
            AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
        }

       // 統計解析的 Bean 數量
        return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
    }

       protected Set doScan(String... basePackages) {
        Assert.notEmpty(basePackages, "At least one base package must be specified");
        Set beanDefinitions = new LinkedHashSet<>();
        for (String basePackage : basePackages) {
            /*  */
            Set candidates = findCandidateComponents(basePackage);
            for (BeanDefinition candidate : candidates) {
                ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
                candidate.setScope(scopeMetadata.getScopeName());
                String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
                if (candidate instanceof AbstractBeanDefinition) {
                    postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
                }
                if (candidate instanceof AnnotatedBeanDefinition) {
                    AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
                }
                if (checkCandidate(beanName, candidate)) {
                    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                    definitionHolder =
                            AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                    beanDefinitions.add(definitionHolder);
                    /*  */
                    registerBeanDefinition(definitionHolder, this.registry);
                }
            }
        }
        return beanDefinitions;
    }

}
/<code>

上述代碼 表示 兩條生產線定位 載入 是不同的, 但從 UML 類圖看 它倆 都繼承了 AbstractApplicationContext 所以 註冊 DI 是相同的

<code>public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {

    // 存儲註冊信息 BeanDefinition
    private final Map beanDefinitionMap = new ConcurrentHashMap<>(256);

        @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {

        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");

        // 校驗解析的 beanDefinition
        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }

        BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
        if (existingDefinition != null) {
            if (!isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            }
            else if (existingDefinition.getRole() < beanDefinition.getRole()) {
                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                if (logger.isInfoEnabled()) {
                    logger.info("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            existingDefinition + "] with [" + beanDefinition + "]");
                }
            }
            else if (!beanDefinition.equals(existingDefinition)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + existingDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            else {
                if (logger.isTraceEnabled()) {
                    logger.trace("Overriding bean definition for bean '" + beanName +
                            "' with an equivalent definition: replacing [" + existingDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {
            if (hasBeanCreationStarted()) {
                // 註冊的過程中需要線程同步, 以保證數據的一致性
                synchronized (this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    if (this.manualSingletonNames.contains(beanName)) {
                        Set updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
                        updatedSingletons.remove(beanName);
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            }
            else {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                this.manualSingletonNames.remove(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }

        // 檢查是否已經註冊過同名的 beanDefinition
        if (existingDefinition != null || containsSingleton(beanName)) {
            // 重置所有已經註冊過的 beanDefinition 緩存
            resetBeanDefinition(beanName);
        }
    }
}    /<code>

總攬全局, 可以看到我們講的 IOC 與 DI 只是眾多 Spring 生命週期中的一部分.

<code>public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {
    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 1. 調用容器準備的刷新方法, 獲取容器的當前時間, 同時給容器設置同步標識
            prepareRefresh();

            // 2.  告訴子類啟動 refreshBeanFactory()方法, Bean定義資源文件的載入從子類的 refreshBeanFactory() 方法啟動
            // 繼承了 AbstractRefreshableApplicationContext 的容器子類可以調用, 從 UML 圖上看 X 生產線可以,A 生產線不行
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // 3. 為 BeanFactory 配置容器特性, 例如類加載器, 事件處理器等
            prepareBeanFactory(beanFactory);

            try {
                // 4. 為容器的某些子類指定的特殊的 Post 事件處理器
                postProcessBeanFactory(beanFactory);

                // 5.  調用所有註冊的 BeanFactoryPostProcessor 的 Bean
                invokeBeanFactoryPostProcessors(beanFactory);

                // 6. 為 BeanFactory 註冊 Post 事件處理器
                // BeanPostProcessor 是Bean 後置處理器, 用於監聽容器觸發的事件
                registerBeanPostProcessors(beanFactory);

                // 7. 初始化信息源, 和國際化相關
                initMessageSource();

                // 8. 初始化容器事件傳播器
                initApplicationEventMulticaster();

                // 9. 調用子類的某些特殊的Bean的初始化方法
                onRefresh();

                // 10. 為事件傳播器註冊事件監聽器
                registerListeners();

                // 11.  初始化所有剩餘的單例模式Bean (non-lazy-init)
                finishBeanFactoryInitialization(beanFactory);

                // 12. 初始化容器的生命週期事件處理器,併發布容器的生命週期事件
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // 13. 銷燬已經創建的單例Bean,以避免掛起資源。
                destroyBeans();

                // 14. 取消刷新操作, 重置容器的同步標識
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // 15. 重設公共緩存, 可能再也不需要單例bean的元數據了……
                resetCommonCaches();
            }
        }
    }    
}/<code>

DI 依賴注入

悶棍暴打面試官 Spring源碼系列:(一) Spring 如何解決循環依賴

循環依賴就發生在 DI 依賴注入這一步. 接下來我們詳細探討一下 它的原理. 看千遍不如手動搞一遍, 不然只是別人的知識,

依賴注入觸發規則

  • 用戶第一次調用 getBean 方法時, IOC 容器觸發依賴注入
  • Bean 設置為 懶加載, 在需要預實例化 Bean 時觸發依賴注入
悶棍暴打面試官 Spring源碼系列:(一) Spring 如何解決循環依賴

<code>public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {

   // 11.  初始化所有剩餘的單例模式Bean (non-lazy-init)
   protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        ...
       beanFactory.preInstantiateSingletons();
    }   
}

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {

    @Override
    public void preInstantiateSingletons() throws BeansException {

        List beanNames = new ArrayList<>(this.beanDefinitionNames);

        // 觸發所有非惰性單例bean的實例化…
        for (String beanName : beanNames) {
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                if (isFactoryBean(beanName)) {
                    ... 
                }
                else {
                    //  第一次調用 getBean 方法時, IOC 容器觸發當前 Bean的依賴注入與實例化
                    getBean(beanName);
                }
            }
        }
        ...
    }
}


public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
    @Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, false);
    }

        protected  T doGetBean(final String name, @Nullable final Class requiredType,
        @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

            // 根據指定的名稱獲取被管理的 Bean 名稱, 剝離指定名稱中對容器的相關依賴
            // 如果指定的是別名, 將別名轉換為 規範的 Bean 名稱
            final String beanName = transformedBeanName(name);
            Object bean;

            // 先從緩存中讀取是否已經有被創建過的單例模式的 Bean
            // 對於單例模式的Bean 整個 IOC 容器中只創建一次, 不需要重複創建
            Object sharedInstance = getSingleton(beanName);
            // IOC 容器創建單例模式的 Bean 示例對象
            if (sharedInstance != null && args == null) {
                if (logger.isTraceEnabled()) {
                    // 如果在容器中已有指定名稱的單例模式 Bean 被創建, 直接返回已經創建的 Bean
                    if (isSingletonCurrentlyInCreation(beanName)) {
                        logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                                "' that is not fully initialized yet - a consequence of a circular reference");
                    }
                    else {
                        logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
                    }
                }
                // 注意: FactoryBean 是創建對象的工廠 Bean, BeanFactory 是管理 Bean 的工廠
                // 獲取給定 Bean 的實例對象, 主要完成 FactoryBean 的相關處理
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
            }

            else {
                // 緩存中沒有正在創建的 單例模式的 Bean
                // 緩存中已有原型模式的 Bean
                // 但是由於循環依賴導致實例化對象失敗
                if (isPrototypeCurrentlyInCreation(beanName)) {
                    throw new BeanCurrentlyInCreationException(beanName);
                }

                // 對 IOC 容器中是否存在指定名稱的 BeanDefinition 進行檢查
                // 首先檢查是否能對當前的 BeanFactory 中獲取所需要的 Bean,
                // 如果不能則委託當前容器的父容器去查找, 如果還是找不到則沿著容器的繼承體系向父容器查找
                BeanFactory parentBeanFactory = getParentBeanFactory();
                if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                    // 解析指定 Bean 名稱的原始名稱
                    String nameToLookup = originalBeanName(name);
                    if (parentBeanFactory instanceof AbstractBeanFactory) {
                        return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                                nameToLookup, requiredType, args, typeCheckOnly);
                    }
                    else if (args != null) {
                        // 委託父容器根據指定名稱和顯式的參數查找
                        return (T) parentBeanFactory.getBean(nameToLookup, args);
                    }
                    else if (requiredType != null) {
                        // 委託父容器根據指定 名稱和類型查找
                        return parentBeanFactory.getBean(nameToLookup, requiredType);
                    }
                    else {
                        // 委託父容器根據指定 名稱查找
                        return (T) parentBeanFactory.getBean(nameToLookup);
                    }
                }

                // 創建的 Bean 是否需要進行類型驗證, 一般不需要
                if (!typeCheckOnly) {
                    // 向容器標記指定的 Bean 已經被創建
                    markBeanAsCreated(beanName);
                }

                try {
                    // 根據指定 Bean 名稱獲取其父級 Bean 定義
                    // 主要解決 Bean 繼承子類和父類公共屬性問題
                    final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                    checkMergedBeanDefinition(mbd, beanName, args);

                    // 獲取當前 Bean 所有依賴 Bean 的名稱
                    String[] dependsOn = mbd.getDependsOn();
                    /** 如果當前 Bean 有 @DependsOn 依賴的 Bean */
                    if (dependsOn != null) {
                        for (String dep : dependsOn) {
                            if (isDependent(beanName, dep)) {
                                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                            }
                            // 把被依賴 Bean 註冊給當前依賴的 Bean
                            registerDependentBean(dep, beanName);
                            try {
                                // 遞歸調用 getBean()方法, 獲取給當前依賴 Bean
                                getBean(dep);
                            }
                            catch (NoSuchBeanDefinitionException ex) {
                                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                        "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                            }
                        }
                    }

                    /** 創建單例模式的 Bean 的實例對象*/
                    if (mbd.isSingleton()) {
                        // 這裡使用了一個匿名的內部類創建 Bean 實例對象, 並且註冊給所依賴的對象
                            sharedInstance = getSingleton(beanName, () -> {
                                try {
                                    // 創建一個指定的 Bean 的實例對象, 如果有父級繼承, 則會合並子類和父類的定義
                                    return createBean(beanName, mbd, args);
                                }
                                catch (BeansException ex) {
                                    // Explicitly remove instance from singleton cache: It might have been put there
                                    // eagerly by the creation process, to allow for circular reference resolution.
                                    // Also remove any beans that received a temporary reference to the bean.
                                    // 顯式地從容器中單例模式的 Bean 緩存中清除實例對象
                                    destroySingleton(beanName);
                                    throw ex;
                                }
                            });
                        // 獲取給定的 Bean 實例對象
                        bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                    }

                    /** 創建原型模式 Bean 的實例對象*/
                    else if (mbd.isPrototype()) {
                        // 原型模式 (Prototype) 每次都會創建一個新的對象
                        Object prototypeInstance = null;
                        try {
                            // 回調 beforePrototypeCreation() 方法, 默認的功能是註冊當前創建的原型對象
                            beforePrototypeCreation(beanName);
                            // 創建指定 Bean 的對象實例
                            prototypeInstance = createBean(beanName, mbd, args);
                        }
                        finally {
                            // 回調 afterPrototypeCreation() 方法, 默認的功能是告訴 IOC 容器 不再創建指定 Bean 的原型對象
                            afterPrototypeCreation(beanName);
                        }
                        bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                    }

                    /**  創建 Web Bean 的實例對象, 比如 request , session, application 等生命週期*/
                    else {
                        // 要創建的 Bean 既不是單例模式的, 也不是原型模式的, 則根據 Bean 定義資源中
                        // 配置的生命週期範圍, 選擇實例化 Bean 的合適方法, 這種方式在多用於 Web 應用程序中
                        String scopeName = mbd.getScope();
                        final Scope scope = this.scopes.get(scopeName);
                        // 如果Bean 定義資源中沒有配置生命週期範圍, 則Bean定義不合法
                        if (scope == null) {
                            throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                        }
                        try {
                            // 這裡又使用了一個匿名內部類, 獲取一個指定生命週期範圍的實例
                            Object scopedInstance = scope.get(beanName, () -> {
                                beforePrototypeCreation(beanName);
                                try {
                                    return createBean(beanName, mbd, args);
                                }
                                finally {
                                    afterPrototypeCreation(beanName);
                                }
                            });
                            // 獲取指定 Bean 的實例對象
                            bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                        }
                        catch (IllegalStateException ex) {
                            ....
                        }
                    }
                }
                catch (BeansException ex) {
                    cleanupAfterBeanCreationFailure(beanName);
                    throw ex;
                }
        }
...

        return (T) bean;
    }
}

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {

        // 封裝被創建的 Bean 對象
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }

        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = instanceWrapper.getWrappedInstance();
        // 獲取實例化對象的類型
        Class> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        // 調用 PostProcessor 後置處理器
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                ...
                }
                mbd.postProcessed = true;
            }
        }

        //  向容器中 緩存單例模式的 Bean 對象, 以防止循環引用
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            // 這裡是一個匿名內部類, 為了循環引用, 儘早持有對象的引用
            // 第二個參數是回調接口,實現的功能是將切面動態織入 bean
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Bean 對象的初始化, 依賴注入在此觸發
        Object exposedObject = bean;
        try {
            // 將 Bean 實例對象封裝, 並且將 Bean 定義中配置的屬性值賦給實例對象
            populateBean(beanName, mbd, instanceWrapper);
            // 調用初始化方法,例如 init-method
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }

        if (earlySingletonExposure) {
            // 獲取指定名稱的已註冊的單例模式 Bean 對象
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                // 根據名稱獲取 的已註冊的 Bean 和正在實例化的 Bean 是同一個
                if (exposedObject == bean) {
                    // 當前實例化的 Bean 初始化完成
                    exposedObject = earlySingletonReference;
                }
                // 當前 Bean 依賴其他 Bean, 並且當發生循環引用時不允許創建新的實例對象
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set actualDependentBeans = new LinkedHashSet 
<>(dependentBeans.length); // 獲取當前 Bean 所依賴的其他 Bean for (String dependentBean : dependentBeans) { // 對依賴 Bean 進行類型檢查 if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } if (!actualDependentBeans.isEmpty()) { ... } } } } // 註冊完成依賴注入的 Bean try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }/<code>

後話

Mason 能看懂源碼,主要有兩方面在起作用,

一方面是因為水滴石穿的不懈努力,客觀上起了作用,

一方面是因為 Mason 通過讀毛選掌握了克服困難的方法論, 主觀上起了作用,

推薦大家參加 毛三公的B站活動 #我在讀毛選#


分享到:


相關文章: