亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

spring解決循環(huán)依賴的簡(jiǎn)單方法

瀏覽:119日期:2023-08-13 16:19:27

Spring內(nèi)部如何解決循環(huán)依賴,一定是單默認(rèn)的單例Bean中,屬性互相引用的場(chǎng)景。比如幾個(gè)Bean之間的互相引用:

spring解決循環(huán)依賴的簡(jiǎn)單方法

或者

spring解決循環(huán)依賴的簡(jiǎn)單方法

setter方式原型,prototype

原型(Prototype)的場(chǎng)景是不支持循環(huán)依賴的,因?yàn)椤皃rototype”作用域的Bean,為每一個(gè)bean請(qǐng)求提供一個(gè)實(shí)例,Spring容器不進(jìn)行緩存,因此無(wú)法提前暴露一個(gè)創(chuàng)建中的Bean,會(huì)拋出異常。

構(gòu)造器參數(shù)循環(huán)依賴

Spring容器會(huì)將每一個(gè)正在創(chuàng)建的Bean 標(biāo)識(shí)符放在一個(gè)“當(dāng)前創(chuàng)建Bean池”中,Bean標(biāo)識(shí)符在創(chuàng)建過(guò)程中將一直保持在這個(gè)池中。

因此如果在創(chuàng)建Bean過(guò)程中發(fā)現(xiàn)自己已經(jīng)在“當(dāng)前創(chuàng)建Bean池”里時(shí)將拋出BeanCurrentlyInCreationException異常表示循環(huán)依賴;而對(duì)于創(chuàng)建完畢的Bean將從“當(dāng)前創(chuàng)建Bean池”中清除掉。

Spring容器先創(chuàng)建單例A,A依賴B,然后將A放在“當(dāng)前創(chuàng)建Bean池”中,此時(shí)創(chuàng)建B,B依賴C,然后將B放在“當(dāng)前創(chuàng)建Bean池”中,此時(shí)創(chuàng)建C,C又依賴A, 但是,此時(shí)A已經(jīng)在池中,所以會(huì)報(bào)錯(cuò),,因?yàn)樵诔刂械腂ean都是未初始化完的,所以會(huì)依賴錯(cuò)誤 ,(初始化完的Bean會(huì)從池中移除)。

setter方式單例,默認(rèn)方式

那么默認(rèn)單例的屬性注入場(chǎng)景,Spring是如何支持循環(huán)依賴的?

既然,要解決循環(huán)依賴,那肯定存在著依賴,我們假設(shè)有兩個(gè)類:

A和B,A->B,B->A,且二者是通過(guò)@Autowired相互注入的。

我們假設(shè)從A開(kāi)始創(chuàng)建,那就是先創(chuàng)建A對(duì)象,然后創(chuàng)建B對(duì)象,再通過(guò)反射把B對(duì)象set到A對(duì)象的屬性上去(fieldB.set(a, b)),在創(chuàng)建B的時(shí)候發(fā)現(xiàn)它又依賴于A,這時(shí)候同樣地,我要尋找一個(gè)A對(duì)象set到B的屬性上去,但是我們的系統(tǒng)中只能存在一個(gè)A對(duì)象(單例)。

為了解決這個(gè)問(wèn)題,需要再前面創(chuàng)建A對(duì)象的時(shí)候就把它保存起來(lái)?我們假設(shè)保存在緩存中,后面B對(duì)象要使用的時(shí)候先去緩存中查找一下不就OK了嘛?!

所以,解決循環(huán)依賴的方法就是保存所有創(chuàng)建的對(duì)象,后面創(chuàng)建對(duì)象的時(shí)候有依賴的情況先去緩存中找一下,找到了直接set到那個(gè)正在創(chuàng)建的對(duì)象的屬性上,沒(méi)找到就創(chuàng)建一個(gè)新的對(duì)象給那個(gè)正在創(chuàng)建的對(duì)象,并保存到緩存中。

實(shí)際上,Spring中也是這么干的,只不過(guò)它的緩存不只一個(gè),而是有四個(gè)。

具體可以看下這邊文章。

https://www.jb51.net/article/195897.htm

Spring解決循環(huán)依賴

首先,Spring內(nèi)部維護(hù)了三個(gè)Map,也就是我們通常說(shuō)的三級(jí)緩存。

在Spring的DefaultSingletonBeanRegistry類中,類上方掛著這三個(gè)Map:

singletonObjects 它是我們最熟悉的朋友,俗稱“單例池”“容器”,緩存創(chuàng)建完成單例Bean的地方。 singletonFactories 映射創(chuàng)建Bean的原始工廠 earlySingletonObjects 映射Bean的早期引用,也就是說(shuō)在這個(gè)Map里的Bean不是完整的,甚至還不能稱之為“Bean”,只是一個(gè)Instance.

后兩個(gè)Map其實(shí)是“墊腳石”級(jí)別的,只是創(chuàng)建Bean的時(shí)候,用來(lái)借助了一下,創(chuàng)建完成就清掉了。

為什么成為后兩個(gè)Map為墊腳石,假設(shè)最終放在singletonObjects的Bean是你想要的一杯“涼白開(kāi)”。

那么Spring準(zhǔn)備了兩個(gè)杯子,即singletonFactories和earlySingletonObjects來(lái)回“倒騰”幾番,把熱水晾成“涼白開(kāi)”放到singletonObjects中

循環(huán)依賴的本質(zhì)

定義兩個(gè)類A與B:

public class A { private B b; public B getB() { return b; } public void setB(B b) { this.b = b; }}

public class B { public A getA() { return a; } public void setA(A a) { this.a = a; } private A a;}

public class CircularDependency { private static Map<String, Object> cacheMap = new HashMap<>(2); public static void main(String[] args) throws Exception { // 假裝掃描出來(lái)的對(duì)象 Class[] classes = { A.class, B.class }; // 假裝項(xiàng)目初始化實(shí)例化所有bean for (Class aClass : classes) { getBean(aClass); } // check System.out.println(getBean(B.class).getA() == getBean(A.class)); System.out.println(getBean(A.class).getB() == getBean(B.class)); } private static <T> T getBean(Class<T> beanClass) throws Exception{ // 本文用類名小寫(xiě) 簡(jiǎn)單代替bean的命名規(guī)則 String beanName = beanClass.getSimpleName().toLowerCase(); // 如果已經(jīng)是一個(gè)bean,則直接返回 if (cacheMap.containsKey(beanName)) { return (T) cacheMap.get(beanName); } // 將對(duì)象本身實(shí)例化 Object object = beanClass.getDeclaredConstructor().newInstance(); // 放入緩存 cacheMap.put(beanName, object); // 把所有字段當(dāng)成需要注入的bean,創(chuàng)建并注入到當(dāng)前bean中 Field[] fields = object.getClass().getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); // 獲取需要注入字段的class Class<?> fieldClass = field.getType(); String fieldBeanName = fieldClass.getSimpleName().toLowerCase(); // 如果需要注入的bean,已經(jīng)在緩存Map中,那么把緩存Map中的值注入到該field即可 // 如果緩存沒(méi)有 繼續(xù)創(chuàng)建 field.set(object, cacheMap.containsKey(fieldBeanName) ? cacheMap.get(fieldBeanName) : getBean(fieldClass)); } // 屬性填充完成,返回 return (T) object; }}

這段代碼的效果,其實(shí)就是處理了循環(huán)依賴,并且處理完成后,cacheMap中放的就是完整的“Bean”了。

總結(jié)

到此這篇關(guān)于spring解決循環(huán)依賴的文章就介紹到這了,更多相關(guān)spring解決循環(huán)依賴內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Spring
相關(guān)文章:
主站蜘蛛池模板: 麻豆传媒在线完整视频 | 国产成人一区二区三区在线播放 | 色片免费 | 国语对白91 | 一级二级黄色片 | 中国一级黄色片子 | 国产精品免费观看视频播放 | 丝袜足交在线播放 | 午夜国产大片免费观看 | 天天色天天碰 | 日韩中文字幕网站 | 国产九色在线 | 99久久国产综合精品网成人影院 | 色片在线观看 | 亚洲国产精品线播放 | 999色综合| 免费国产一级特黄aa大 | 国语一级毛片私人影院 | 国产福利视频一区 | 久久亚洲网 | 美日韩免费视频 | 国产永久免费视频m3u8 | 亚洲一区二区三区久久久久 | 黄色片一级免费 | 亚州毛色毛片免费观看 | 久久久精品视频在线观看 | 一级全黄视频 | 亚洲精品欧美精品一区二区 | 国产在线爱做人成小视频 | 被黑人操 | 欧美啪啪毛片一区二区 | 国产aaa三级 | 成人做爰又黄又爽免费视频 | 一级爱片| 欧美一级成人 | 狠狠色丁香久久婷婷综合_中 | 久青草视频97国内免费影视 | 亚洲影视自拍揄拍愉拍 | 亚洲色图套图超市 | 91午夜精品亚洲一区二区三区 | 国产精品免费看久久久久 |