循環依賴其實就是循環引⽤,也就是兩個或者兩個以上的 Bean互相持有對⽅,最終造成閉環。⽐如A 依賴於B,B依賴於C,C⼜依賴於Ajava
注意,這⾥不是函數的循環調⽤,是對象的相互依賴關係。循環調⽤其實就是⼀個死循環,除⾮有終結條件spring
Spring中循環依賴場景有:ide
其中,構造器的循環依賴問題⽆法解決,只能拋出 BeanCurrentlyInCreationException異常,在解決屬性循環依賴時,spring採⽤的是提早暴露對象的⽅法
set
⽅法產⽣循環依賴,Spring都 會直接報錯處理。Spring的循環依賴的理論依據基於Java的引⽤傳遞,當得到對象的引⽤時,對象的屬性是能夠延後設置的,可是構造器必須是在獲取引⽤以前函數
Spring經過setXxx或者@Autowired⽅法解決循環依賴實際上是經過提早暴露⼀個ObjectFactory對象來完成的,簡單來講ClassA在調⽤構造器完成對象初始化以後,在調⽤ClassA的setClassB⽅法以前就把ClassA實例化的對象經過ObjectFactory提早暴露到Spring容器中this
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isDebugEnabled()) { logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } //將初始化後的對象提早已ObjectFactory對象注⼊到容器中addSingletonFactory(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { return getEarlyBeanReference(beanName, mbd,bean); } });
ClassB調⽤setClassA⽅法,Spring從容器中獲取ClassA ,由於第⼀步中已經提早暴露了ClassA,所以能夠獲取到ClassA實例spa