循環依賴其實就是循環引⽤,也就是兩個或者兩個以上的 Bean 互相持有對⽅,最終造成閉環。⽐如A依賴於B,B依賴於C,C⼜依賴於A
java
Spring中循環依賴場景有:spring
其中,構造器的循環依賴問題⽆法解決,只能拋出 BeanCurrentlyInCreationException 異常,在解決屬性循環依賴時,spring採⽤的是提早暴露對象的⽅法。緩存
//lagouBen 依賴於 ItBean public class LagouBean { private ItBean itBean; public void setItBean(ItBean itBean) { this.itBean = itBean; } public LagouBean() { System.out.println("LagouBean 構造器"); } }
//ItBean 依賴於 LagouBen public class ItBean { private LagouBean lagouBean; public void setLagouBean(LagouBean lagouBean) { this.lagouBean = lagouBean; } public ItBean() { System.out.println("ItBean...構造器"); } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="lagouBean" class="com.lagou.edu.LagouBean" > <property name="ItBean" ref="itBean>"></property> </bean> <bean id="itBean" class="com.lagou.edu.ItBean" > <property name="LagouBean" ref="lagouBean>"></property> </bean> </beans>
A依賴於B ,B 依賴於A函數
A在建立過程當中 :this
首先會建立Bean實例(僅僅調用構造方法,可是還沒有設置屬性,經過反射完成對象的初始化),prototype
而後判斷是不是單例,是否有循環依賴。code
把建立好的Bean實例放入三級緩存——singletonFactories
xml
而後將要給A Bean裝配屬性,發現依賴B
對象
調用deGetBean() 想拿到B,首先從一級緩存(singletonObjects)中拿,而後從二級緩存中(earlySingletonObjects)拿,而後從三級緩存(singletonFactories)拿,都拿不到,那就開始建立B Bean
blog
把建立好的B Bean實例放入三級緩存——singletonFactories,發現依賴於A
調用deGetBean() 想拿到A,首先從一級緩存(singletonObjects)中拿,而後從二級緩存中(earlySingletonObjects)拿,都沒拿到。而後從三級緩存中拿,拿到了
拿到A Bean以後如上圖,放到二級緩存(earlySingletonObjects)中,而後從三級緩存(singletonFactories)中刪除。而後給B bean賦值了。
此時B Bean 就裝配好了 放入一級緩存池中。
B 裝配好了以後,A 就能順利的裝配了,而後調用addSingleton()
方法,把A 從二級三級緩存中刪除,而後放到一級緩存也就是單例池中。
完成
注意:
這個案例中,B不會放到二級緩存,只有在B依賴的一個對象還沒有實例化的時候纔會把B放到二級緩存。例如:
A依賴B,B依賴A和C,C依賴B。 先建立A,把還沒有賦值的A放到三級緩存,而後賦值B,找不到B,而後建立B,而後把還沒有賦值的B放到三級緩存,而後在建立B的過程當中從三級緩存找A(同時把A從三級緩存中刪除而後加入到二級緩存),而後B還有個屬性C,賦值C,從緩存中找不到C,而後建立C,而後把還沒有賦值的B放到三級緩存,建立C的過程當中發現C依賴於B,而後能夠從三級緩存中找到B,而後把B放到二級緩存,C就裝配完畢了,放到一級緩存。同時B也有了A和C,B裝配完畢了,放到一級緩存。 A依賴B,B已經OK了,那麼A也裝配完畢了。
/** Cache of singleton factories: bean name to ObjectFactory. */ //三級緩存 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); /** Cache of early singleton objects: bean name to bean instance. */ //二級緩存 private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16); /** Cache of singleton objects: bean name to bean instance. */ //一級緩存 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);