八字真言:“三級快取,提前暴露”
此文只是介紹簡單的情況便於理解,實際上場景會更復雜、情況會更多,但是原理相通。
一、什麼是迴圈依賴?
從字面上來理解就是A依賴B的同時B也依賴了A,就像下面這樣
上圖是簡單的迴圈依賴,也會存在A依賴B,B依賴C,C依賴A這種迴圈,或者更復雜的情況。
(在實際工作中應該儘量避免出現迴圈依賴的情況)
二、什麼情況下迴圈依賴可以被處理?
三、Spring是如何解決的迴圈依賴?
三級快取:
一級快取 : Map<string,object> singletonObjects,單例池,用於儲存例項化、屬性賦值(注入)、初始化完成的 bean 例項
二級快取 : Map<string,object> earlySingletonObjects,早期曝光物件,用於儲存例項化完成的 bean 例項
三級快取 : Map<string,objectfactory<?>> singletonFactories,早期曝光物件工廠,用於儲存 bean 建立工廠,以便於後面擴充套件有機會建立代理物件。
流程圖:
總結:
假如testService1依賴testService2,testService2依賴testService1
Bean初始化流程:
- 建立 testService1例項,例項化的時候把 testService1 物件⼯⼚放⼊三級快取,並提前先暴露出來;
- testService1 注⼊屬性時,發現依賴 testService2,此時 testService2 還沒有被建立出來,所以去例項化 testService2;
- 同樣,testService2注⼊屬性時發現依賴 testService1,它就會從快取裡找 testService1物件。依次從⼀級到三級快取查詢 testService1,從三級快取透過物件⼯⼚拿到 testService1,發現 testService1雖然不太完善,但是存在,把 testService1 放⼊⼆級快取,同時刪除三級快取中的 testService1,此時,testService2 已經例項化並且初始化完成,把testService2放入⼀級快取
- 接著testService1繼續屬性賦值,順利從⼀級快取拿到例項化且初始化完成的testService2物件,testService1物件建立也完成,刪除⼆級快取中的 testService1,同時把testService1放⼊⼀級快取
- 最後,⼀級快取中儲存著例項化、初始化都完成的 testService1、testService2 物件