前言:在doCreateBean方法中還遺留一個問題沒有分析:循環依賴。循環依賴在Spring中是很是重要的一個知識點,所以單獨進行分析。web
循環依賴就是循環引用,兩個或兩個以上的bean互相引用對方,最終造成一個閉環。如A依賴B,B依賴C,C依賴A。以下圖所示:緩存
循環依賴其實就是一個死循環的過程,在初始化A的時候發現引用了B,則就會去初始化B,而後發現B又引用C,則又去初始化C,在初始化C的時候,再次發現C引用了A,則又去初始化A,這樣就處於死循環,除非有終結條件。websocket
Spring中循環依賴的場景有兩種:session
構造器循環依賴app
表示經過構造器注入構成的循環依賴,此依賴是沒法解決的,只能拋出BeanCurrentlyInCreationException異常。socket
setter循環依賴函數
表示經過setter注入方式構成的循環依賴,對於setter注入形成的循環依賴,Spring只解決單例模式下的循環依賴,對於其餘做用域的循環依賴,則拋出BeanCurrentlyInCreationException異常。爲何Spring只解決單例模式下的循環依賴呢,這裏首先了解下Spring的幾個做用域。this
Spring的scope做用域spa
從上面對Spring中scope做用域的介紹,也可大體瞭解爲何Spring中只解決單例模式下的循環依賴了,由於其餘做用域對象的生命週期並不與Spring IOC容器一致,而且最主要的一點是Spring並不會對除了單例模式的bean作緩存,所以Spring只能解決單例模式下的循環依賴。prototype
首先在看bean的加載的入口,在doGetBean方法中有以下代碼:
首先會根據beanName從單例bean緩存中獲取,若是不爲空,則直接返回,前面已經分析了該方法,這裏再次提出來。
1 // DefaultListableBeanFactory 2 protected Object getSingleton(String beanName, boolean allowEarlyReference) { 3 // 從單例緩存中加載Bean 4 Object singletonObject = this.singletonObjects.get(beanName); 5 // 緩存中bean爲空,且當前bean正在建立 6 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { 7 // 作同步 8 synchronized (this.singletonObjects) { 9 // 從earlySingletonObjects集合中獲取 10 singletonObject = this.earlySingletonObjects.get(beanName); 11 // earlySingletonObjects集合中沒有,其容許提早建立 12 if (singletonObject == null && allowEarlyReference) { 13 // 從singletonFactories中獲取對應的ObjectFactory 14 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); 15 if (singletonFactory != null) { 16 // 獲取bean 17 singletonObject = singletonFactory.getObject(); 18 // 將bean添加到earlySingletonObjects集合中 19 this.earlySingletonObjects.put(beanName, singletonObject); 20 // 從singletonFactories中移除對應的 21 this.singletonFactories.remove(beanName); 22 } 23 } 24 } 25 } 26 return singletonObject; 27 }
分析:
這裏注意isSingletonCurrentlyInCreation函數,判斷當前bean是否正在被建立,這裏就是判斷beanName是否在singletonsCurrentlyInCreation集合中,那麼正在被建立的bean是合適添加進去的呢?仍是在doGetBean方法中
1 // DefaultSingletonBeanRegistry 2 public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { 3 Assert.notNull(beanName, "Bean name must not be null"); 4 // 作同步 5 synchronized (this.singletonObjects) { 6 // 從緩存中檢查一遍 7 // 由於singlton模式其實已經複用了建立的bean,因此該步驟必須檢查 8 Object singletonObject = this.singletonObjects.get(beanName); 9 // 爲空,開始進行加載 10 if (singletonObject == null) { 11 if (this.singletonsCurrentlyInDestruction) { 12 throw new BeanCreationNotAllowedException(beanName, 13 "Singleton bean creation not allowed while singletons of this factory are in destruction " + 14 "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); 15 } 16 if (logger.isDebugEnabled()) { 17 logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); 18 } 19 // 加載前置處理 其實就是打一個標記 20 beforeSingletonCreation(beanName); 21 // 首先將新的newSingleton設置爲false 22 boolean newSingleton = false; 23 boolean recordSuppressedExceptions = (this.suppressedExceptions == null); 24 if (recordSuppressedExceptions) { 25 this.suppressedExceptions = new LinkedHashSet<>(); 26 } 27 try { 28 // 初始化bean 29 // 該過程實際上是調用createBean()方法 這裏是一個回調方法 30 singletonObject = singletonFactory.getObject(); 31 newSingleton = true; 32 } catch (IllegalStateException ex) { 33 // Has the singleton object implicitly appeared in the meantime -> 34 // if yes, proceed with it since the exception indicates that state. 35 singletonObject = this.singletonObjects.get(beanName); 36 if (singletonObject == null) { 37 throw ex; 38 } 39 } catch (BeanCreationException ex) { 40 if (recordSuppressedExceptions) { 41 for (Exception suppressedException : this.suppressedExceptions) { 42 ex.addRelatedCause(suppressedException); 43 } 44 } 45 throw ex; 46 } finally { 47 if (recordSuppressedExceptions) { 48 this.suppressedExceptions = null; 49 } 50 // 一堆異常處理後,進行後置處理 移除標誌 51 afterSingletonCreation(beanName); 52 } 53 // 新的bean 加入緩存中 54 if (newSingleton) { 55 addSingleton(beanName, singletonObject); 56 } 57 } 58 return singletonObject; 59 }
分析:
注意第20行代碼beforeSingletonCreation函數。
1 // DefaultSingletonBeanRegistry 2 protected void beforeSingletonCreation(String beanName) { 3 // 這裏會添加到正在建立bean的集合中 4 // 注意第一個條件,若是存在,則爲false,直接短路 5 // 只有當第一個條件不存在[false]時,纔會去進行添加操做 6 if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { 7 throw new BeanCurrentlyInCreationException(beanName); 8 } 9 }
分析:
這裏就會將正在建立的beanName添加到singletonsCurrentlyInCreation,若是出現構造函數的循環依賴bean注入,則會在此處拋出BeanCurrentlyCreationException異常,具體能夠跟着代碼調試一把,就能夠更清楚的知曉流程。
接下來繼續回到單例模式的循環依賴中:
在加載bean時,首先從單例緩存中獲取bean對象。
注意這裏涉及到三個集合:
1 /** 2 * Cache of singleton objects: bean name to bean instance. 3 * 存放的是單例 bean 的映射。 4 * <p> 5 * 對應關係爲 bean name --> bean instance 6 */ 7 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); 8 9 /** 10 * Cache of singleton factories: bean name to ObjectFactory.<br/> 11 * 存放的是 ObjectFactory,能夠理解爲建立單例 bean 的 factory 。 12 * <p> 13 * 對應關係是 bean name --> ObjectFactory 14 */ 15 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); 16 17 /** 18 * Cache of early singleton objects: bean name to bean instance.<br/> 19 * 存放的是早期的 bean,對應關係也是 bean name --> bean instance。 20 * <p> 21 * 它與 {@link #singletonFactories} 區別在於 earlySingletonObjects 中存放的 bean 不必定是完整。 22 * <p> 23 * 從 {@link #getSingleton(String)} 方法中,咱們能夠了解,bean 在建立過程當中就已經加入到 earlySingletonObjects 中了。 24 * 因此當在 bean 的建立過程當中,就能夠經過 getBean() 方法獲取。 25 * <p> 26 * 這個 Map 也是【循環依賴】的關鍵所在。 27 */ 28 private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
這三個緩存集合就是解決Spring中循環依賴的所在,具體流程:
若是從單例緩存中獲得bean對象,則會調用getObjectForBeanInstance方法進一步處理,由於從緩存中獲得的bean是最原始的bean,並不必定是最終所須要的bean對象。
上面分析了從緩存中獲取bean對象,可是緩存中的值是從什麼地方添加進來的呢?若是你調試過源碼會發現這樣一段代碼:
1 // AbstractAutowireCapableBeanFactory 2 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && 3 isSingletonCurrentlyInCreation(beanName));// 當前單例bean是否正在被建立 4 if (earlySingletonExposure) { 5 if (logger.isDebugEnabled()) { 6 logger.debug("Eagerly caching bean '" + beanName + 7 "' to allow for resolving potential circular references"); 8 } 9 // 提早將建立的bean實例加入到singletonFactories中 10 // 爲了後期避免循環依賴 11 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); 12 }
分析:
當一個bean知足三個條件,則會被加入到緩存中。三個條件以下:
DefaultSingletonBeanRegistry#addSingletonFactroy
1 protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { 2 Assert.notNull(singletonFactory, "Singleton factory must not be null"); 3 synchronized (this.singletonObjects) { 4 if (!this.singletonObjects.containsKey(beanName)) { 5 this.singletonFactories.put(beanName, singletonFactory); 6 this.earlySingletonObjects.remove(beanName); 7 this.registeredSingletons.add(beanName); 8 } 9 } 10 }
分析:
上面介紹的了三級緩存[singletonFactories]與二級緩存[earlySingletonObjects]的出處,接下來看一級緩存的出處:
在DefaultSingletonBeanRegistry#getSingleton函數中:
1 public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { 2 Assert.notNull(beanName, "Bean name must not be null"); 3 // 作同步 4 synchronized (this.singletonObjects) { 5 // 從緩存中檢查一遍 6 // 由於singlton模式其實已經複用了建立的bean,因此該步驟必須檢查 7 Object singletonObject = this.singletonObjects.get(beanName); 8 // 爲空,開始進行加載 9 if (singletonObject == null) { 10 if (this.singletonsCurrentlyInDestruction) { 11 throw new BeanCreationNotAllowedException(beanName, 12 "Singleton bean creation not allowed while singletons of this factory are in destruction " + 13 "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); 14 } 15 if (logger.isDebugEnabled()) { 16 logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); 17 } 18 // 加載前置處理 其實就是打一個標記 19 beforeSingletonCreation(beanName); 20 // 首先將新的newSingleton設置爲false 21 boolean newSingleton = false; 22 boolean recordSuppressedExceptions = (this.suppressedExceptions == null); 23 if (recordSuppressedExceptions) { 24 this.suppressedExceptions = new LinkedHashSet<>(); 25 } 26 try { 27 // 初始化bean 28 // 該過程實際上是調用createBean()方法 這裏是一個回調方法 29 singletonObject = singletonFactory.getObject(); 30 newSingleton = true; 31 } catch (IllegalStateException ex) { 32 // Has the singleton object implicitly appeared in the meantime -> 33 // if yes, proceed with it since the exception indicates that state. 34 singletonObject = this.singletonObjects.get(beanName); 35 if (singletonObject == null) { 36 throw ex; 37 } 38 } catch (BeanCreationException ex) { 39 if (recordSuppressedExceptions) { 40 for (Exception suppressedException : this.suppressedExceptions) { 41 ex.addRelatedCause(suppressedException); 42 } 43 } 44 throw ex; 45 } finally { 46 if (recordSuppressedExceptions) { 47 this.suppressedExceptions = null; 48 } 49 // 一堆異常處理後,進行後置處理 移除標誌 50 afterSingletonCreation(beanName); 51 } 52 // 新的bean 加入緩存中 53 if (newSingleton) { 54 addSingleton(beanName, singletonObject); 55 } 56 } 57 return singletonObject; 58 } 59 }
分析:
這裏關注第54行處:addSingleton函數。
1 // DefaultSingletonBeanRegistry 2 protected void addSingleton(String beanName, Object singletonObject) { 3 synchronized (this.singletonObjects) { 4 this.singletonObjects.put(beanName, singletonObject); 5 this.singletonFactories.remove(beanName); 6 this.earlySingletonObjects.remove(beanName); 7 this.registeredSingletons.add(beanName); 8 } 9 }
分析:
這裏就是將bean加入一級緩存中[singletonObjects],同時remove二級緩存和三級緩存中值,由於bean已經被建立成功了,二級緩存與三級緩存也就不須要了。
從上面分析過程能夠知道爲何Spring只解決單例模式下的循環依賴了吧?
單例模式下循環依賴解決流程:
若是你看過《Spring源碼深度解析》這本書,還能發現以下流程圖:
注:看圖說話,筆者最爲喜歡!其實去親身調試一下循環依賴的代碼,可能會有更加深入的認識。
by Shawn Chen,2019.04.29,下午。