福建參觀禁毒展覽館的網(wǎng)站建設(shè)網(wǎng)站設(shè)計(jì)公司報(bào)價(jià)
什么是循環(huán)依賴 ?
一個(gè)或多個(gè)對象之間存在直接或間接的依賴關(guān)系,這種依賴關(guān)系構(gòu)成一個(gè)環(huán)形調(diào)用,有下面 3 種方式。
我們看一個(gè)簡單的 Demo,對標(biāo)“情況 2”。
@Service
public class Louzai1 {@Autowiredprivate Louzai2 louzai2;public void test1() {}
}@Service
public class Louzai2 {@Autowiredprivate Louzai1 louzai1;public void test2() {}
}
這是一個(gè)經(jīng)典的循環(huán)依賴,它能正常運(yùn)行,后面我們會(huì)通過源碼的角度,解讀整體的執(zhí)行流程。
三級緩存
解讀源碼流程之前,spring 內(nèi)部的三級緩存邏輯必須了解,要不然后面看代碼會(huì)蒙圈。
第一級緩存:singletonObjects,用于保存實(shí)例化、注入、初始化完成的 bean 實(shí)例;
第二級緩存:earlySingletonObjects,用于保存實(shí)例化完成的 bean 實(shí)例;
第三級緩存:singletonFactories,用于保存 bean 創(chuàng)建工廠,以便后面有機(jī)會(huì)創(chuàng)建代理對象。
這是最核心,我們直接上源碼:
執(zhí)行邏輯:
先從“第一級緩存”找對象,有就返回,沒有就找“二級緩存”;
找“二級緩存”,有就返回,沒有就找“三級緩存”;
找“三級緩存”,找到了,就獲取對象,放到“二級緩存”,從“三級緩存”移除。
原理執(zhí)行流程
我把“情況 2”執(zhí)行的流程分解為下面 3 步,是不是和“套娃”很像 ?
整個(gè)執(zhí)行邏輯如下:
1、在第一層中,先去獲取 A 的 Bean,發(fā)現(xiàn)沒有就準(zhǔn)備去創(chuàng)建一個(gè),然后將 A 的代理工廠放入“三級緩存”(這個(gè) A 其實(shí)是一個(gè)半成品,還沒有對里面的屬性進(jìn)行注入),但是 A 依賴 B 的創(chuàng)建,就必須先去創(chuàng)建 B;
2、在第二層中,準(zhǔn)備創(chuàng)建 B,發(fā)現(xiàn) B 又依賴 A,需要先去創(chuàng)建 A;
3、在第三層中,去創(chuàng)建 A,因?yàn)榈谝粚右呀?jīng)創(chuàng)建了 A 的代理工廠,直接從“三級緩存”中拿到 A 的代理工廠,獲取 A 的代理對象,放入“二級緩存”,并清除“三級緩存”;
4、回到第二層,現(xiàn)在有了 A 的代理對象,對 A 的依賴完美解決(這里的 A 仍然是個(gè)半成品),B 初始化成功;
5、回到第一層,現(xiàn)在 B 初始化成功,完成 A 對象的屬性注入,然后再填充 A 的其它屬性,以及 A 的其它步驟(包括 AOP),完成對 A 完整的初始化功能(這里的 A 才是完整的 Bean)。
6、將 A 放入“一級緩存”。
Spring Bean的生命周期
getBean(a)–>實(shí)例化A–>屬性注入–>初始化A–>銷毀
三級緩存的作用:
singletonObjects(一級緩存):存放實(shí)例化–>代理–>屬性注入–>初始化后的對象
earlySingletonObjects(二級緩存):存放實(shí)例化–>代理–>屬性注入后的對象
singletonFactories(三級緩存):存放對象工廠,可以從對象工廠中拿到還未屬性注入的對象(對象工廠便于創(chuàng)建代理對象)
當(dāng)未添加三級緩存時(shí)候:
當(dāng)加入三級緩存后: