所謂循環依賴就是多個Bean之間依賴關係造成一個閉環,例如A->B->C->...->A 這種狀況,固然,最簡單的循環依賴就是2個Bean之間互相依賴:A->B(A依賴B), B->A(B依賴A) 。在Spring中,若是A->B,那麼在建立A的過程當中會去建立B,在建立B(或B的依賴)的過程當中又發現B->A,這個時候就出現了循環依賴的現象。spring
spring中的循環依賴只有當緩存
這兩個條件知足的狀況下是沒問題的。可是若是是經過構造器依賴,或者不是單例模式的狀況下循環依賴就會拋出異常BeanCurrentlyInCreationException。下面從代碼層面上解析一下爲何。app
爲何最早介紹Prototype的循環依賴呢,由於能夠順便介紹在Spring中建立Bean的流程核心流程:在AbstractFoctory的doGetBean的方法。這個方法很長,這裏只寫出核心邏輯,並在註解上註明了我的理解:ide
protected <T> T doGetBean( final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { final String beanName = transformedBeanName(name); Object bean; //嘗試獲取單例對象,由於spring大部分的bean都是單例的,因此這裏先嚐試可否獲取。 registered singletons. Object sharedInstance = getSingleton(beanName); //單例存在的狀況下,那麼beanName返回的確定是單例類,可是這裏還須要判斷是否是FactoryBean if (sharedInstance != null && args == null) { ... //FactoryBean應該返回getObject()對象 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { //走到這裏,有可能beanName是單例模式,但以前並無實例化,或者是Prototype類型。 //首先判斷不是循環依賴,這裏的循環依賴指的是Prototype類型 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } try { final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // 若是是單例,則建立單例模式 if (mbd.isSingleton()) { // !!!這裏是解決單例循環依賴的關鍵,後面再分析 sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { throw ex; } } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } else if (mbd.isPrototype()) { // 原型模式,則建立一個新對象. Object prototypeInstance = null; try { /*這裏是Prototype循環依賴的問題,會記錄在map中beanName, 若是在解決當前Bean的依賴過程當中還依賴當前Bean, 則說明了出現了循環依賴 */ beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { //對應beforePrototypeCreation(),從map中移除 afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } ... } } ... return (T) bean; }
能夠看出,該流程中就考慮了Prototype的循環依賴的問題,只要在建立Prototype的Bean中出現循環依賴那麼就拋出異常。可是在singleton的狀況下,則經過另外的方式來解決。函數
在上面介紹中,出現了一個很關鍵的地方:ui
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { throw ex; } } });
這個getSingleton涉及到了ObjectFactory這個接口類,這個接口的功能和FactoryBean相似,可是主要是用來解決循環依賴的。在初始化過程同決定返回的Singleton對象是。關於單例的對象的建立,又要介紹一下DefaultSingletonBeanRegistry這個類,這個類主要用來幫助建立單例模式,其中主要的屬性:this
/** 緩存建立的單例對象: bean名字 --> bean對象 */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256); /** 緩存單例的factory,就是ObjectFactory這個東西,: bean name --> ObjectFactory */ private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16); /** 也是緩存建立的單例對象,功能和singletonObjects不同, 在bean構形成功以後,屬性初始化以前會把對象放入到這裏, 主要是用於解決屬性注入的循環引用: bean name --> bean instance */ private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16); /** 記錄在建立單例對象中循環依賴的問題,還記得Prototype中又記錄建立過程當中依賴的map嗎? 在Prototype中只要出現了循環依賴就拋出異常,而在單例中會嘗試解決 */ private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(16));
如今回過來看getSingleton(beanName, new ObjectFactory<Object>()這個方法的實現。prototype
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { synchronized (this.singletonObjects) { //嘗試在singletonObjects中獲取 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { //不存在則建立 //把當前beanName加入到singletonsCurrentlyInCreation中 beforeSingletonCreation(beanName); try { singletonObject = singletonFactory.getObject(); } ... finally { ... //從singletonsCurrentlyInCreation中刪除beanName afterSingletonCreation(beanName); } } return (singletonObject != NULL_OBJECT ? singletonObject : null); } }
這段邏輯是否是和Prototype中解決循環相似,這裏其實就是調用了ObjectFactory的getObject()獲取對象,回過頭去看前面代碼,ObjectFactory的getObject()方法實際調用的是createBean(beanName, mbd, args)。說到createBean(beanName, mbd, args)又不得不說AbstractAutowireCapableBeanFactory這個類,主要功能就是完成依賴注入的Bean的建立,這個類的createBean方法代碼以下,注意註解說明:debug
@Override protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException { ... Object beanInstance = doCreateBean(beanName, mbdToUse, args); ... } protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException { // 實例化bean BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { //若是沒實例化則建立新的BeanWrapper //若是是經過構造器注入,這裏是一個關鍵點 /* 由於在A初始化的時候發現構造函數依賴B,就會去實例化B, 而後B也會運行到這段邏輯,構造函數中發現依賴A, 這個時候就會拋出循環依賴的異常 */ instanceWrapper = createBeanInstance(beanName, mbd, args); } //若是當前是單例,而且allowCircularReferences爲true(默認就是true,除非咱們不但願Spring幫咱們解決) boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { /* !!!這裏很重要,把構形成功,但屬性還沒注入的 的bean加到singletonFactory中,這樣再解決A的依賴 過程當中若是依賴A,就把這個半成品返回回去。 */ addSingletonFactory(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { return getEarlyBeanReference(beanName, mbd, bean); } }); } Object exposedObject = bean; try { //自動注入屬性 populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null) { exposedObject = initializeBean(beanName, exposedObject, mbd); } } ... return exposedObject; }
註解已經註明了個人理解。就再也不贅述code
上面代碼是我一邊debug一個寫下的,如今寫完了,根據本身的理解總結一下。
若是A--構造依賴->B,B--屬性依賴-->A,例如:
@Component public class BeanA { private BeanB beanB; @Autowired public BeanA(BeanB beanB) { this.beanB = beanB; } } @Component public class BeanB { @Autowired private BeanA beanA; }
這種狀況會異常嗎?提示:都有可能