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