Spring 解決迴圈依賴原始碼分析

2021-10-06 02:25:28 字數 3010 閱讀 4589

迴圈依賴就是n個類之間迴圈巢狀引用,如a依賴b,b又依賴a,你中有我,我中有你。例項化a時發現需要b屬性,於是去例項化b,發現需要a屬性。。。如果spring不對這種迴圈依賴進行處理程式就會無限執行,導致記憶體溢位、系統崩潰。

迴圈依賴又分為構造器迴圈依賴屬性迴圈依賴,由於spring不支援構造器迴圈依賴,會直接報錯,所以接下來只討論屬性迴圈依賴。

bean例項化可以大致分為三步

其中迴圈依賴發生在例項化注入屬性這兩個步驟裡。

例項化a時,將a這個並不完整的物件快取起來,這樣當b例項化後,注入a的時候,能夠從容器中獲取到a物件,完成初始化。最後將b物件注入到a中,a完成初始化。

spring引入了**快取來解決迴圈依賴的問題

/** 一級快取,快取初始化完成的bean */

private

final mapsingletonobjects = new concurrenthashmap(256);

/** 二級快取,快取原始bean(還未填充屬性),用於解決迴圈依賴 */

private

final mapearlysingletonobjects = new hashmap(16);

/** **快取,快取bean工廠物件,用於解決迴圈依賴 */

private

final map> singletonfactories = new hashmap(16);複製**

當獲取單例bean時,會依次訪問一級快取、二級快取、**快取,快取命中則返回。

getbean是從容器中獲取bean的入口方法,它裡面又呼叫了dogetbean方法,來看一下這個方法。

protected  t dogetbean(final string name, @nullable final class requiredtype,

@nullable final object args, boolean typecheckonly) throws bean***ception catch (bean***ception ex)

});

}

return (t) bean;

}複製**

這個方法裡面有兩個名稱為getsingleton的方法,第乙個getsingleton是從快取中查詢bean,如果快取未命中,則走第二個getsingleton,嘗試建立目標物件並注入依賴

當第一次呼叫dogetbean獲取a物件,第乙個getsingleton返回空,進入第二個getsingleton建立a物件,注入b物件。呼叫dogetbean獲取b,第乙個getsingleton返回空,進入第二個getsingleton建立b物件,獲取並注入原始a物件,此時b物件初始化完成。最後將b物件注入a中,a完成初始化。

先看第乙個getsingleton的原始碼

@nullable

protected object getsingleton(string beanname, boolean allowearlyreference)

}}

}

return singletonobject;

}複製**

首先從一級快取singletonobjects獲取目標物件,若不存在且目標物件被標記為建立中,從二級快取earlysingletonobjects中獲取bean。如果不存在,繼續訪問**快取singletonfactories,得到bean工廠物件,通過工廠物件獲取目標物件。將目標物件放入二級快取,刪除**快取

第二個getsingleton方法

getsingleton(string beanname, objectfactory> singletonfactory)

public object getsingleton(string beanname, objectfactory> singletonfactory) 

// ......

// 返回 singletonobject

return (singletonobject != null_object ? singletonobject : null);

}

}複製**

該方法的主要邏輯是呼叫singletonfactory的getobject()方法建立目標物件,然後將bean放入快取中。

接下來看一下getobject方法的實現,由於在dogetbean中呼叫getsingleton時第二個引數是用匿名內部類的方式傳參,實際上呼叫的是createbean方法,而createbean又呼叫了docreatebean

protected object docreatebean(final string beanname, final rootbeandefinition mbd, final object args)

throws beancreationexception

});}object exposedobject = bean;

// ......

// ☆ 填充屬性,解析依賴

// ......

// 返回 bean 例項

return exposedobject;

protected void addsingletonfactory(string beanname, objectfactory> singletonfactory)

}}複製**

方法的主要邏輯如下

用createbeaninstance建立目標物件將物件新增到singletonfactories快取

populatebean注入依賴spring在例項化bean時,會先建立當前bean物件,放入快取中,然後以遞迴的方式獲取所依賴的屬性。當注入屬性時,如果出現了迴圈依賴則會從快取中獲取依賴物件。

Spring迴圈依賴解決原始碼解析

相關方法 1 spring無法解決構造方法注入引起的迴圈依賴問題 2 spring無法解決多例物件的迴圈依賴問題,因為多例物件是不進行快取的 第一級快取 快取已經完成了例項化和屬性設定的單例物件 單例物件快取 private final map singletonobjects newconcurr...

Spring迴圈依賴原始碼Debug

首先我們要搞清楚兩個概念 例項化 初始化 例項化 堆記憶體中申請一塊記憶體空間,類似租賃好房子,自己的家具東西還沒有搬家進去 初始化屬性填充 完成屬性的各種賦值,類似裝修 家電家具進場 快取 四大方法 快取 第一層singletonobjects存放的是已經初始化好了的bean。第二層earlysi...

Spring迴圈依賴 原始碼上分析

一 spring bean 的建立 四個階段 二 defaultsingletonbeanregistry 三個主要不同階段bean的map 今天所要主要關注是 例項化 instantiation createbeaninstance 和 屬性賦值 populate populatebean 量階段...