一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - 淺入淺出的講解Spring循環(huán)依賴問題

淺入淺出的講解Spring循環(huán)依賴問題

2022-02-16 15:05一條coding Java教程

循環(huán)依賴其實就是循環(huán)引用,也就是兩個或則兩個以上的bean互相持有對方,最終形成閉環(huán),下面這篇文章主要給大家介紹了關(guān)于Spring循環(huán)依賴問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下

 

前言

最近有粉絲問到了循環(huán)依賴問題,以后再有人問你,拿這篇“吊打”他。

 

概念

 

什么是循環(huán)依賴?

多個bean之間相互依賴,形成了一個閉環(huán)。比如:A依賴于B、B依賴于C、C依賴于A。

淺入淺出的講解Spring循環(huán)依賴問題

通常來說,如果問Spring容器內(nèi)部如何解決循環(huán)依賴,一定是指默認(rèn)的單例Bean中,基于set方法構(gòu)造注入的屬性互相引用的場景。

循環(huán)依賴的種類及能否解決如下:

 

名稱 是否可解決循環(huán)依賴
構(gòu)造器循環(huán)依賴
Setter循環(huán)依賴
Prototype作用域的循環(huán)依賴

 

 

報錯信息

Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name ‘myDao": Requested bean is currently in creation: Is there an unresolvable circular reference?

翻譯一下

通過構(gòu)造函數(shù)參數(shù) 0 表示的依賴關(guān)系未得到滿足;嵌套的異常是 創(chuàng)建名稱為"myDao"的bean時出錯。請求的Bean目前正在創(chuàng)建中。是否存在一個無法解決的循環(huán)引用?

異常信息:bean當(dāng)前創(chuàng)建異常org.springframework.beans.factory.BeanCurrentlyInCreationException。

 

通俗版理解

 

兩人對峙

現(xiàn)在甲乙兩個人,互相對峙,甲說乙先放,乙說甲先放。就是不開槍。

哎,就是玩!

相信這個場景大家在電視劇里都見過吧,最后一般是“反派死于話多”。

但是回到我們 spring里,我們是不希望有人死亡的,也就是必須兩個bean都創(chuàng)建出來,怎么辦?

 

必須有一人妥協(xié)

解決方案就是:必須有一個人先妥協(xié)。

甲說:我退一步,我先把彈夾卸了,你把槍放下。

乙一聽就感動了,滿含熱淚的拿槍放下了。

甲一看乙沒有打自己,也熱淚盈眶,兩人緊緊相擁。

從此過上了幸福美滿的生活……

 

Spring版理解

回到我們spring里,先回顧一下bean的生命周期:

  • 實例化
  • 屬性賦值
  • 初始化
  • 銷毀

簡單理解一下的上面的過程

 

實例化和初始化什么區(qū)別?

是不是只差了中間賦值的過程,那只實例化的bean可以使用嗎?

當(dāng)然不可以!

也就是說只實例化的bean是一個半成品,初始化之后才是成品,才可以使用。

現(xiàn)在A依賴B,B依賴A。

A對B說:我要完整的你

b也對a:我要完整的你

ok,兩人打起來了,拿槍對峙。怎么解決?是不是得一個人妥協(xié)。

a說:算了吧,你給我個你的半成品,我將就一下。

b心里尋思,他用我的半成品創(chuàng)建一個完整的a,然后我就可以創(chuàng)建了。

心里這么想,嘴上就爽快答應(yīng)著:行,沒問題。

如此,a創(chuàng)建了完整的自己,b拿著a也完成了創(chuàng)建。

問題解決。

真的解決了嗎?成品和半成品都存在哪里呢?

這就不得不提到大名鼎鼎的三級緩存。

 

三級緩存

spring提供了三級緩存來存放成品和半成品及工廠。位于DefaultSingletonBeanRegistry類中。

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {   
	/**
	*一級緩存:單例池
	*存放已經(jīng)初始化的bean――成品
	*/
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
    /**
	*三級緩存:單例工廠的高速緩存
	*存放生成bean的工廠
	*/
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
    /**
	*二級緩存:早期單例對象的高速緩存
	*存放已經(jīng)實例化但未初始化(未填充屬性)的的bean――半成品
	*/
    private final Map<String, Object> earlySingletonObjects = new HashMap(16);
}

淺入淺出的講解Spring循環(huán)依賴問題

 

創(chuàng)建過程(簡易版)

如果你是面試突擊,建議把簡易版被下來就可以應(yīng)付面試了
等有時間再看源碼版

假如A依賴B,B依賴A,那么這兩個類之間形成了一個循環(huán)依賴

  • A先開始創(chuàng)建,通過其無參構(gòu)造方法創(chuàng)建bean的實例,并將其實例放入到「二級緩存」提前暴露出來。A停止。
  • B開始創(chuàng)建,先去「一級緩存」找A的成品,找不到,再去「二級緩存」里找,還找不到,再去「三級緩存」里找,找到了A的創(chuàng)建工廠,通過工廠,拿到A的半成品,并將A放到「二級緩存」。
  • 拿到A后,B完成創(chuàng)建,將自己放入「一級緩存」。
  • 此時A繼續(xù)創(chuàng)建,同樣從「一級緩存」開始找,拿到B后完成創(chuàng)建,將自己放入「一級緩存」。

 

創(chuàng)建過程(源碼版)

源碼版建議配合spring源碼邊debug邊食用。

1、當(dāng)我們在調(diào)用getBean()獲取bean時,實際調(diào)用的是doGetBean() 方法。doGetBean() 想要獲取 beanA ,于是調(diào)用 getSingleton() 方法從緩存中查找 beanA

2、在 getSingleton() 方法中,從「一級緩存」中查找,沒有,返回 null

3、doGetBean() 方法中獲取到 beanA 為 null ,于是走對應(yīng)的處理邏輯,調(diào)用 getSingleton() 的重載方法(參數(shù)為 ObjectFactory 的)

4、在 getSingleton()方法中,先將 beanA_name 添加到一個集合中,用于標(biāo)記該 bean 正在創(chuàng)建中,然后回調(diào)匿名內(nèi)部類的 createBean 方法

5、進入 AbstractAutowireCapableBeanFactory#doCreateBean,先反射調(diào)用構(gòu)造器創(chuàng)建出 beanA 的實例,然后判斷,是否為單例,是否允許提前暴露引用(對于單例一般為true)、是否正在創(chuàng)建中(即是否是在第四步的集合中)判斷為 true 則將 beanA 添加到「三級緩存」中

6、對 beanA 進行屬性填充,此時檢測到 beanA 依賴于 beanB ,于是查找 beanB

7、調(diào)用 doGetBean() 方法,和上面 beanA 的過程一樣,到緩存中查詢 beanB ,沒有則創(chuàng)建,然后給 beanB 填充屬性

8、此時 beanB 依賴于 beanA ,調(diào)用 getSingleton() 獲取 beanA ,依次從一級、二級、三級緩存中找、此時從「三級緩存」中獲取到 beanA 的創(chuàng)建工廠,通過創(chuàng)建工廠獲取到 singletonObject ,此時這個 singletonObject 指向的就是上面在 doCreateBean() 方法中實例化的 beanA

9、這樣 beanB 就獲取到了 beanA 的依賴,于是 beanB 順利完成初始化,并將 beanA 從「三級緩存」移動到「二級緩存」中

10、隨后 beanA 繼續(xù)他的屬性填充工作,此時也獲取到了 beanB ,beanA 也隨之完成了創(chuàng)建,回到 getSingleton() 方法中繼續(xù)向下執(zhí)行,將 beanA 從「二級緩存」移動到「一級緩存」中

淺入淺出的講解Spring循環(huán)依賴問題

 

最后

到此這篇關(guān)于Spring循環(huán)依賴問題的文章就介紹到這了,更多相關(guān)Spring循環(huán)依賴內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!

原文鏈接:https://juejin.cn/post/7017631372923633694

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产午夜精品一区二区三区不卡 | 久久青青草视频在线观 | 色橹橹 | 久久伊人电影 | 国内自拍视频在线观看 | 亚洲2017久无码 | 好 舒服 好 粗 好硬免费视频 | 护士的小嫩嫩好紧好舒服 | 色一情一乱一伦 | 操bb视频| 成年人网站免费在线观看 | 亚洲国产影院 | 国产一区二区视频在线观看 | 精品四虎国产在免费观看 | 免费观看欧美成人禁片 | 国产va免费精品高清在线观看 | 波多野结衣快播 | 精品无码人妻一区二区免费AV | 青草香蕉精品视频在线观看 | 特黄特色大片免费高清视频 | 欧美a欧美1级 | 毛片在线免费视频 | 九九久久国产精品大片 | 图片专区小说专区卡通动漫 | 四虎精品在线视频 | 日韩免费毛片视频杨思敏 | 小辣椒精品福利视频导航 | 国产偷啪视频一区 | 2023最新伦理片 | 国产自拍专区 | 变态 另类 人妖小说 | 午夜国产精品福利在线观看 | 色臀网站| 女教师系列三上悠亚在线观看 | 1024亚洲精品国产 | 男男浴室吸乳play | 日韩在线观看一区二区不卡视频 | 国产一区二区三区免费在线视频 | 色天天综合色天天看 | 18性夜影院午夜寂寞影院免费 | 亚洲 欧美 日韩 国产 视频 |