最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文教你如何通過三級(jí)緩存解決Spring循環(huán)依賴

 更新時(shí)間:2023年07月20日 09:31:53   作者:Java知識(shí)庫(kù)  
這篇文章主要介紹了如何通過三級(jí)緩存解決?Spring?循環(huán)依賴,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考價(jià)值,需要的朋友可以參考下

以下內(nèi)容基于 Spring6.0.4。

1. 循環(huán)依賴

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

首先,什么是循環(huán)依賴?這個(gè)其實(shí)好理解,就是兩個(gè) Bean 互相依賴,類似下面這樣:

@Service
public class AService {
    @Autowired
    BService bService;
}
@Service
public class BService {
    @Autowired
    AService aService;
}

AService 和 BService 互相依賴:

這個(gè)應(yīng)該很好理解。

1.2 循環(huán)依賴的類型

一般來說,循環(huán)依賴有三種不同的形態(tài),上面 1.1 小節(jié)是其中一種。

另外兩種分別是三者依賴,如下圖:

這種循環(huán)依賴一般隱藏比較深,不易發(fā)覺。

還有自我依賴,如下圖:

一般來說,如果我們的代碼中出現(xiàn)了循環(huán)依賴,則說明我們的代碼在設(shè)計(jì)的過程中可能存在問題,我們應(yīng)該盡量避免循環(huán)依賴的發(fā)生。不過一旦發(fā)生了循環(huán)依賴,Spring 默認(rèn)也幫我們處理好了,當(dāng)然這并不能說明循環(huán)依賴這種代碼就沒問題。實(shí)際上在目前最新版的 Spring 中,循環(huán)依賴是要額外開啟的,如果不額外配置,發(fā)生了循環(huán)依賴就直接報(bào)錯(cuò)了。
另外,Spring 并不能處理所有的循環(huán)依賴,后面松哥會(huì)和大家進(jìn)行分析。

2. 循環(huán)依賴解決思路

2.1 解決思路

那么對(duì)于循環(huán)依賴該如何解決呢?其實(shí)很簡(jiǎn)單,中加加入一個(gè)緩存就可以了,小伙伴們來看下面這張圖:

我們?cè)谶@里引入了一個(gè)緩存池。

當(dāng)我們需要?jiǎng)?chuàng)建 AService 的實(shí)例的時(shí)候,會(huì)首先通過 Java 反射創(chuàng)建出來一個(gè)原始的 AService,這個(gè)原始 AService 可以簡(jiǎn)單理解為剛剛 new 出來(實(shí)際是剛剛通過反射創(chuàng)建出來)還沒設(shè)置任何屬性的 AService,此時(shí),我們把這個(gè) AService 先存入到一個(gè)緩存池中。

接下來我們就需要給 AService 的屬性設(shè)置值了,同時(shí)還要處理 AService 的依賴,這時(shí)我們發(fā)現(xiàn) AService 依賴 BService,那么就去創(chuàng)建 BService 對(duì)象,結(jié)果創(chuàng)建 BService 的時(shí)候,發(fā)現(xiàn) BService 依賴 AService,那么此時(shí)就先從緩存池中取出來 AService 先用著,然后繼續(xù) BService 創(chuàng)建的后續(xù)流程,直到 BService 創(chuàng)建完成后,將之賦值給 AService,此時(shí) AService 和 BService 就都創(chuàng)建完成了。

可能有小伙伴會(huì)說,BService 從緩存池中拿到的 AService 是一個(gè)半成品,并不是真正的最終的 AService,但是小伙伴們要知道,咱們 Java 是引用傳遞(也可以認(rèn)為是值傳遞,只不過這個(gè)值是內(nèi)存地址),BService 當(dāng)時(shí)拿到的是 AService 的引用,說白了就是一塊內(nèi)存地址而已,根據(jù)這個(gè)地址找到的就是 AService,所以,后續(xù)如果 AService 創(chuàng)建完成后,BService 所拿到的 AService 就是完整的 AService 了。

那么上面提到的這個(gè)緩存池,在 Spring 容器中有一個(gè)專門的名字,就叫做 earlySingletonObjects,這是 Spring 三級(jí)緩存中的二級(jí)緩存,這里保存的是剛剛通過反射創(chuàng)建出來的 Bean,這些 Bean 還沒有經(jīng)歷過完整生命周期,Bean 的屬性可能都還沒有設(shè)置,Bean 需要的依賴都還沒有注入進(jìn)來。另外兩級(jí)緩存分別是:

  • singletonObjects:這是一級(jí)緩存,一級(jí)緩存中保存的是所有經(jīng)歷了完整生命周期的 Bean,即一個(gè) Bean 從創(chuàng)建、到屬性賦值、到各種處理器的執(zhí)行等等,都經(jīng)歷過了,就存到 singletonObjects 中,當(dāng)我們需要獲取一個(gè) Bean 的時(shí)候,首先會(huì)去一級(jí)緩存中查找,當(dāng)一級(jí)緩存中沒有的時(shí)候,才會(huì)考慮去二級(jí)緩存。
  • singletonFactories:這是三級(jí)緩存。在一級(jí)緩存和二級(jí)緩存中,緩存的 key 是 beanName,緩存的 value 則是一個(gè) Bean 對(duì)象,但是在三級(jí)緩存中,緩存的 value 是一個(gè) Lambda 表達(dá)式,通過這個(gè) Lambda 表達(dá)式可以創(chuàng)建出來目標(biāo)對(duì)象的一個(gè)代理對(duì)象。

有的小伙伴可能會(huì)覺得奇怪,按照上文的介紹,一級(jí)緩存和二級(jí)緩存就足以解決循環(huán)依賴了,為什么還冒出來一個(gè)三級(jí)緩存?那就得考慮 AOP 的情況了!

2.2 存在 AOP 怎么辦

上面給大家介紹的是普通的 Bean 創(chuàng)建,那確實(shí)沒有問題。但是 Spring 中還有一個(gè)非常重要的能力,那就是 AOP。

說到這里,我得先和小伙伴么說一說 Spring 中 AOP 的創(chuàng)建流程。

正常來說是我們首先通過反射獲取到一個(gè) Bean 的實(shí)例,然后就是給這個(gè) Bean 填充屬性,屬性填充完畢之后,接下來就是執(zhí)行各種 BeanPostProcessor 了,如果這個(gè) Bean 中有需要代理的方法,那么系統(tǒng)就會(huì)自動(dòng)配置對(duì)應(yīng)的后置處理器,松哥舉一個(gè)簡(jiǎn)單例子,假設(shè)我有如下一個(gè) Service:

@Service
public class UserService {
    @Async
    public void hello() {
        System.out.println("hello>>>"+Thread.currentThread().getName());
    }
}

那么系統(tǒng)就會(huì)自動(dòng)提供一個(gè)名為
AsyncAnnotationBeanPostProcessor 的處理器,在這個(gè)處理器中,系統(tǒng)會(huì)生成一個(gè)代理的 UserService 對(duì)象,并用這個(gè)對(duì)象代替原本的 UserService。

那么小伙伴們要搞清楚的是,原本的 UserService 和新生成的代理的 UserService 是兩個(gè)不同的對(duì)象,占兩塊不同的內(nèi)存地址!?。?/p>

我們?cè)賮砘仡櫹旅孢@張圖:

如果 AService 最終是要生成一個(gè)代理對(duì)象的話,那么 AService 存到緩存池的其實(shí)還是原本的 AService,因?yàn)榇藭r(shí)還沒到處理 AOP 那一步(要先給各個(gè)屬性賦值,然后才是 AOP 處理),這就導(dǎo)致 BService 從緩存池里拿到的 AService 是原本的 AService,等到 BService 創(chuàng)建完畢之后,AService 的屬性賦值才完成,接下來在 AService 后續(xù)的創(chuàng)建流程中,AService 會(huì)變成了一個(gè)代理對(duì)象了,不是緩存池里的 AService 了,最終就導(dǎo)致 BService 所依賴的 AService 和最終創(chuàng)建出來的 AService 不是同一個(gè)。

為了解決這個(gè)問題,Spring 引入了三級(jí)緩存 singletonFactories。

singletonFactories 的工作機(jī)制是這樣的(假設(shè) AService 最終是一個(gè)代理對(duì)象):

當(dāng)我們創(chuàng)建一個(gè) AService 的時(shí)候,通過反射剛把原始的 AService 創(chuàng)建出來之后,先去判斷當(dāng)前一級(jí)緩存中是否存在當(dāng)前 Bean,如果不存在,則:

  • 首先向三級(jí)緩存中添加一條記錄,記錄的 key 就是當(dāng)前 Bean 的 beanName,value 則是一個(gè) Lambda 表達(dá)式 ObjectFactory,通過執(zhí)行這個(gè) Lambda 可以給當(dāng)前 AService 生成代理對(duì)象。
  • 然后如果二級(jí)緩存中存在當(dāng)前 AService Bean,則移除掉。

現(xiàn)在繼續(xù)去給 AService 各個(gè)屬性賦值,結(jié)果發(fā)現(xiàn) AService 需要 BService,然后就去創(chuàng)建 BService,創(chuàng)建 BService 的時(shí)候,發(fā)現(xiàn) BService 又需要用到 AService,于是就先去一級(jí)緩存中查找是否有 AService,如果有,就使用,如果沒有,則去二級(jí)緩存中查找是否有 AService,如果有,就使用,如果沒有,則去三級(jí)緩存中找出來那個(gè) ObjectFactory,然后執(zhí)行這里的 getObject 方法,這個(gè)方法在執(zhí)行的過程中,會(huì)去判斷是否需要生成一個(gè)代理對(duì)象,如果需要就生成代理對(duì)象返回,如果不需要生成代理對(duì)象,則將原始對(duì)象返回即可。最后,把拿到手的對(duì)象存入到二級(jí)緩存中以備下次使用,同時(shí)刪除掉三級(jí)緩存中對(duì)應(yīng)的數(shù)據(jù)。這樣 AService 所依賴的 BService 就創(chuàng)建好了。

接下來繼續(xù)去完善 AService,去執(zhí)行各種后置的處理器,此時(shí),有的后置處理器想給 AService 生成代理對(duì)象,發(fā)現(xiàn) AService 已經(jīng)是代理對(duì)象了,就不用生成了,直接用已有的代理對(duì)象去代替 AService 即可。

至此,AService 和 BService 都搞定。

本質(zhì)上,singletonFactories 是把 AOP 的過程提前了。

3. 小結(jié)

總的來說,Spring 解決循環(huán)依賴把握住兩個(gè)關(guān)鍵點(diǎn):

  • 提前暴露:剛剛創(chuàng)建好的對(duì)象還沒有進(jìn)行任何賦值的時(shí)候,將之暴露出來放到緩存中,供其他 Bean 提前引用(二級(jí)緩存)。
  • 提前 AOP:A 依賴 B 的時(shí)候,去檢查是否發(fā)生了循環(huán)依賴(檢查的方式就是將正在創(chuàng)建的 A 標(biāo)記出來,然后 B 需要 A,B 去創(chuàng)建 A 的時(shí)候,發(fā)現(xiàn) A 正在創(chuàng)建,就說明發(fā)生了循環(huán)依賴),如果發(fā)生了循環(huán)依賴,就提前進(jìn)行 AOP 處理,處理完成后再使用(三級(jí)緩存)。

原本 AOP 這個(gè)過程是屬性賦完值之后,再由各種后置處理器去處理 AOP 的(AbstractAutoProxyCreator),但是如果發(fā)生了循環(huán)依賴,就先 AOP,然后屬性賦值,最后等到后置處理器執(zhí)行的時(shí)候,就不再做 AOP 的處理了。

不過需要注意,三級(jí)緩存并不能解決所有的循環(huán)依賴。

以上就是一文教你如何通過三級(jí)緩存解決Spring循環(huán)依賴的詳細(xì)內(nèi)容,更多關(guān)于三級(jí)緩存解決Spring循環(huán)依賴的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論

高州市| 宜川县| 云阳县| 上虞市| 怀远县| 噶尔县| 罗山县| 田林县| 广宁县| 青川县| 百色市| 万盛区| 弋阳县| 普兰店市| 宜君县| 开原市| 吉安市| 信宜市| 阳城县| 平顶山市| 湘阴县| 富蕴县| 眉山市| 南川市| 象州县| 浦县| 岑巩县| 封开县| 应用必备| 城步| 惠水县| 大兴区| 防城港市| 霍邱县| 宝山区| 阳曲县| 贞丰县| 桦南县| 革吉县| 建宁县| 兴义市|