Spring解決循環依賴三級緩存講解


Spring5默認通過三級緩存來解決循環依賴,但是必須要求Bean是單例的,如果scope=prototype則無法解決.Spring的構造器注入無法解決循環依賴問題,setter方法注入可以解決.

所謂Spring的三級緩存是指DefaultSingletonBeanRegistry中的三個Map

// 一級緩存 緩存完成初始化的bean 完成整個生命周期
private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
// 三級緩存 緩存bean工廠
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
// 二級緩存 緩存早期暴露的bean 還未完成生命周期
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);

Spring IOC初始化中有四個核心方法

getSingleton: 從容器中獲取單例的bean
doCreateBean: 容器中獲取不到就創建bean
populateBean: 創建完成了需要給bean填充屬性
addSingleton: 填充完了,再添加到容器的一級緩存中
如果存在循環依賴Spring內部如何解決? 如 A依賴B B依賴A

A創建過程中需要B,於是A將自己放在三級緩存中,去實例化B
B在實例化的時候發現需要A,於是B先去查詢一級緩存,方法沒有A,再取查詢二級緩存發現還是沒有A,再查詢三級緩存找到了A,然后將三級緩存A注入到自己的屬性中,然后從三級緩存中將A刪除,加入到二級緩存,並將B自己放入一級緩存中,此時B初始化完畢
然后回來接着創建A,此時B已經在一級緩存了,直接從一級緩存中拿到B,然后完成A的初始化,最后再將A自己放入一級緩存
從源碼的角度查看Spring如何解決循環依賴?

調用doGetBean()方法,想要獲取beanA,於是調用getSingleton()方法從緩存中查找BeanA
getSingleton先從一級緩存中查找,沒有返回null
一級緩存中沒有找到調用getSingleton的重載方法 參數為ObjectFactory
在getSingleton方法中,將BeanA_name添加到一個集合中,用於標記該bean正在創建中.然后回調匿名內部類的createBean方法
進入AbstractAutowireCapableBeanFactory#doCreateBean,先反射調用構造器創建beanA,然后判斷,是否為單例和是否允許早期暴露(單例默認為true),是否正在創建中(是否在第4步的集合中),判斷為true將beanA添加到 三級緩存中
對beanA進行屬性填充,此時檢測到beanA依賴到beanB,於是開始查找beanB
調用doGetBean()方法,依然同上面步驟一樣,調用getSingleton方法嘗試從緩存中獲取
getSingleton 依次從一級緩存,二級緩存中查找beanA,都沒有找到,最終從三級緩存中找到beanA的創建工廠,通過創建工廠獲取到singletonObject,此時這個singletonOject指向的就是上面的doCreateBean方法中實例化的beanA
此時beanB就獲取到了beanA的依賴,於是beanB順利完成實例化,並將beanA從三級緩存中移動到二級緩存中,然后將自己beanB放入一級緩存
隨后beanA繼續他的屬性填充,此時發現依賴了B,調用getSingleton嘗試從緩存中獲取
此時beanB在已經在一級緩存中找到,完成BeanA的屬性填充,此時將beanA從二級緩存中刪除,移動到一級緩存

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM