所謂的循環引用,就是A依賴B,B又依賴A,A與B兩個對象相互持有。像下面這種狀況:html
class A { B b; public A(B b) { this.b=b; } } class B { A a; public B(A a ) { this.a=a; } }咱們知道spring在獲取對象或者在加載的時候,觸發依賴注入。例如觸發A對象的依賴注入,發現須要B對象,而此時B尚未初始化,就去實例化B對象,而又須要A對象,這樣就進入了一種死循環狀態,有點像操做系統裏面的死鎖。彷佛這種狀況發生了,Spring就陷入僵局了。顯然Spring有方法去解決這個問題。對於依賴注入的狀況,大體分爲構造注入和設值注入兩種方式,而實際上由於Spring注入的觸發機制不同,這個問題又被分爲singleton對象和prototype(其餘三個做用域大體相同)對象的區別。咱們能夠把問題大體分爲三類。
這種依賴Spring是沒法給你解決的,將會拋出BeanCurrentlyInCreationException異常。來看一下測試代碼java
(1) 定義兩個類 A,B 構成構形成循環依賴的狀況spring
class A { B b; public A(B b) { this.b=b; } } class B { A a; public B(A a ) { this.a=a; } }
<bean id="xiaoA" class="com.songxu.learn.A"> <constructor-arg name="b" ref="xiaoB" /> </bean> <bean id="xiaoB" class="com.songxu.learn.B"> <constructor-arg name="a" ref="xiaoA" /> </bean>
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml"); <span style="font-size:18px;"> </span>(4) 結果拋出了異常,來看一下日誌輸出
2015-08-01 02:39:15,869>>>>[org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] >>>>Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@2ef5e5e3: defining beans [xiaoA,xiaoB]; root of factory hierarchy 2015-08-01 02:39:15,869>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'xiaoA' 2015-08-01 02:39:15,869>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'xiaoA' 2015-08-01 02:39:15,889>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'xiaoB' 2015-08-01 02:39:15,889>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'xiaoB' 2015-08-01 02:39:15,889>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'xiaoA' 2015-08-01 02:39:15,889>>>>[org.springframework.context.support.AbstractApplicationContext]-[WARN] >>>>Exception encountered during context initialization - cancelling refresh attempt org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'xiaoA' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'xiaoB' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'xiaoB' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'xiaoA' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'xiaoA': Requested bean is currently in creation: Is there an unresolvable circular reference?
對於設值注入的狀況,循環依賴是能夠完成的。來看一下測試代碼。緩存
(1) 構造兩個類 A,B 構成循環依賴,而且使用設值注入的方式。app
class CircleA { private CircleB b; public CircleA(CircleB b) { this.b=b; } public CircleB getB() { return b; } public void setB(CircleB b) { this.b = b; } public CircleA() { } } class CircleB { private CircleA a; public CircleA getA() { return a; } public void setA(CircleA a) { this.a = a; } public CircleB(CircleA a) { this.a=a; } public CircleB() { } }
<bean id="circleA" class="com.songxu.learn.CircleA" > <property name="b" ref="circleB"></property> </bean> <bean id="circleB" class="com.songxu.learn.CircleB" > <property name="a" ref="circleA"></property> </bean>
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
2015-08-01 03:41:32,302>>>>[org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] >>>>Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@100fc185: defining beans [circleA,circleB]; root of factory hierarchy 2015-08-01 03:41:32,302>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'circleA' 2015-08-01 03:41:32,302>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'circleA' 2015-08-01 03:41:32,312>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Eagerly caching bean 'circleA' to allow for resolving potential circular references 2015-08-01 03:41:32,312>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'circleB' 2015-08-01 03:41:32,312>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'circleB' 2015-08-01 03:41:32,312>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Eagerly caching bean 'circleB' to allow for resolving potential circular references 2015-08-01 03:41:32,312>>>>[org.springframework.beans.factory.support.AbstractBeanFactory]-[DEBUG] >>>>Returning eagerly cached instance of singleton bean 'circleA' that is not fully initialized yet - a consequence of a circular reference 2015-08-01 03:41:32,322>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Finished creating instance of bean 'circleB' 2015-08-01 03:41:32,322>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Finished creating instance of bean 'circleA' 2015-08-01 03:41:32,322>>>>[org.springframework.beans.factory.support.AbstractBeanFactory]-[DEBUG] >>>>Returning cached instance of singleton bean 'circleB'這個過程是這樣的, A構造空對象放入緩存池中(暫且稱爲A空),觸發了B對象注入,而後去構造B對象,又觸發了對A對象的注入,這個時候緩存中已經有一個空的A對象,就把A空對象注入給B, 而後B構造完成,返回給A,這時A對象已經完成了注入。而同時B中持有的A對象也再也不是A空了, 由於A是單例的,且A完成了注入,此時A=A空。也就完成了整個注入過程。
依然設置A,B兩個類,構成循環依賴,A採用設值注入B,B採用構造器注入A。對於這種狀況,Spring是能夠完成注入的。來查看示例代碼ide
(1) 構造兩個類 A,B 構成循環依賴關係,A採用設值注入B,B採用構造器注入A測試
class A { B b; public B getB() { return b; } public void setB(B b) { this.b = b; } } class B { A a; public B(A a ) { this.a=a; } }
<bean id="xiaoA" class="com.songxu.learn.A"> <constructor-arg name="b" ref="xiaoB" /> </bean> <bean id="xiaoB" class="com.songxu.learn.B"> <constructor-arg name="a" ref="xiaoA" /> </bean>
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml"); <span style="font-size:18px;"> </span>(4) 結果正常,A,B注入完成,查看一下日誌輸出
2015-08-01 04:00:32,884>>>>[org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] >>>>Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@6d00a15d: defining beans [xiaoA,xiaoB]; root of factory hierarchy 2015-08-01 04:00:32,884>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'xiaoA' 2015-08-01 04:00:32,884>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'xiaoA' 2015-08-01 04:00:32,894>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Eagerly caching bean 'xiaoA' to allow for resolving potential circular references 2015-08-01 04:00:32,904>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'xiaoB' 2015-08-01 04:00:32,904>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'xiaoB' 2015-08-01 04:00:32,904>>>>[org.springframework.beans.factory.support.AbstractBeanFactory]-[DEBUG] >>>>Returning eagerly cached instance of singleton bean 'xiaoA' that is not fully initialized yet - a consequence of a circular reference 2015-08-01 04:00:32,914>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Eagerly caching bean 'xiaoB' to allow for resolving potential circular references 2015-08-01 04:00:32,914>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Finished creating instance of bean 'xiaoB' 2015-08-01 04:00:32,924>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Finished creating instance of bean 'xiaoA' 2015-08-01 04:00:32,924>>>>[org.springframework.beans.factory.support.AbstractBeanFactory]-[DEBUG] >>>>Returning cached instance of singleton bean 'xiaoB'
兩個類構成循環依賴而且須要完成Spring注入的惟一條件是,能夠構造一個空的對象放入緩存,不然將會失敗。而這種空對象的構造必須採用設值注入的方式。在後面將給出深度解析。this
依然採用上面的三種狀況去分析spa
(1)類與上面的同樣,只是配置文件稍做修改操作系統
<bean id="xiaoA" class="com.songxu.learn.A" scope="prototype"> <constructor-arg name="b" ref="xiaoB" /> <!-- <property name="b" ref="xiaoB"></property> --> </bean> <bean id="xiaoB" class="com.songxu.learn.B" scope="prototype"> <constructor-arg name="a" ref="xiaoA" /> </bean>
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml"); A xiaoA=(A)applicationContext.getBean("xiaoA");
2015-08-01 04:09:31,425>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'xiaoA' 2015-08-01 04:09:31,435>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'xiaoB' Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'xiaoA' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'xiaoB' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'xiaoB' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'xiaoA' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'xiaoA': Requested bean is currently in creation: Is there an unresolvable circular reference?
(1)類與上面的同樣,只是配置文件稍做修改
<span style="font-size:18px;"><bean id="circleA" class="com.songxu.learn.CircleA" scope="prototype"> <property name="b" ref="circleB"></property> </bean> <bean id="circleB" class="com.songxu.learn.CircleB" scope="prototype" > <property name="a" ref="circleA"></property> </bean> </span>
<span style="font-size:18px;">ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml"); CircleB b=(CircleB)applicationContext.getBean("circleB"); </span>
2015-08-01 04:13:29,505>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'circleB' 2015-08-01 04:13:29,515>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'circleA' Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'circleB' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'circleA' while setting bean property 'a'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'circleA' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'circleB' while setting bean property 'b'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'circleB': Requested bean is currently in creation: Is there an unresolvable circular reference?
測試代碼與上面相似,結果一樣是沒法完成注入,拋出BeanCurrentlyInCreationException異常。
對於prototype來講,只有存在循環引用的狀況,是沒法完成注入的。
這種混合模式在某些狀況下是成立的。這裏只給出一種成功的案例,其餘模式下沒法完成。這一成功的類型是AB兩個類都採用設值注入的方式。
(1) 構造A ,B兩個類,構成循環依賴關係
class CircleA { private CircleB b; public CircleB getB() { return b; } public void setB(CircleB b) { this.b = b; } public CircleA() { } } class CircleB { private CircleA a; public CircleB() { } public CircleA getA() { return a; } public void setA(CircleA a) { this.a = a; } }
<bean id="circleA" class="com.songxu.learn.CircleA" scope="prototype" > <property name="b" ref="circleB"></property> </bean> <bean id="circleB" class="com.songxu.learn.CircleB" > <property name="a" ref="circleA"></property> </bean>
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml"); CircleA A=(CircleA)applicationContext.getBean("circleA"); CircleB B=(CircleB)applicationContext.getBean("circleB"); System.out.println(A==B.getA());
2015-08-01 04:45:08,952>>>>[org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] >>>>Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@100fc185: defining beans [circleA,circleB]; root of factory hierarchy 2015-08-01 04:45:08,952>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'circleB' 2015-08-01 04:45:08,952>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'circleB' 2015-08-01 04:45:08,962>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Eagerly caching bean 'circleB' to allow for resolving potential circular references 2015-08-01 04:45:08,962>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'circleA' 2015-08-01 04:45:08,962>>>>[org.springframework.beans.factory.support.AbstractBeanFactory]-[DEBUG] >>>>Returning eagerly cached instance of singleton bean 'circleB' that is not fully initialized yet - a consequence of a circular reference 2015-08-01 04:45:08,972>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Finished creating instance of bean 'circleA' 2015-08-01 04:45:08,972>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Finished creating instance of bean 'circleB' 2015-08-01 04:45:08,972>>>>[org.springframework.context.support.AbstractApplicationContext]-[DEBUG] >>>>Unable to locate LifecycleProcessor with name 'lifecycleProcessor': using default [org.springframework.context.support.DefaultLifecycleProcessor@1dfe2924] 2015-08-01 04:45:08,972>>>>[org.springframework.beans.factory.support.AbstractBeanFactory]-[DEBUG] >>>>Returning cached instance of singleton bean 'lifecycleProcessor' 2015-08-01 04:45:08,982>>>>[org.springframework.core.env.PropertySourcesPropertyResolver]-[DEBUG] >>>>Searching for key 'spring.liveBeansView.mbeanDomain' in [systemProperties] 2015-08-01 04:45:08,982>>>>[org.springframework.core.env.PropertySourcesPropertyResolver]-[DEBUG] >>>>Searching for key 'spring.liveBeansView.mbeanDomain' in [systemEnvironment] 2015-08-01 04:45:08,982>>>>[org.springframework.core.env.PropertySourcesPropertyResolver]-[DEBUG] >>>>Could not find key 'spring.liveBeansView.mbeanDomain' in any property source. Returning [null] init finished============================================ 2015-08-01 04:45:08,982>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'circleA' 2015-08-01 04:45:08,982>>>>[org.springframework.beans.factory.support.AbstractBeanFactory]-[DEBUG] >>>>Returning cached instance of singleton bean 'circleB' 2015-08-01 04:45:08,982>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Finished creating instance of bean 'circleA' 2015-08-01 04:45:08,982>>>>[org.springframework.beans.factory.support.AbstractBeanFactory]-[DEBUG] >>>>Returning cached instance of singleton bean 'circleB' false
下面的示意圖大體顯示了這個過程的關鍵步驟,關於細節的代碼,能夠查看另外一篇博客。
這個圖中的數字標識了各個過程,紅色填圖的區域表示關鍵步驟,黃色填圖的區域爲logger日誌輸出內容,虛線邊框表明一個方法的內部。
下面是一段 singleon對象循環引用的日誌輸出。用來配合理解這個過程
2015-08-01 09:51:34,966>>>>[org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] >>>>Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@100fc185: defining beans [circleA,circleB]; root of factory hierarchy 2015-08-01 09:51:34,966>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'circleA' 2015-08-01 09:51:34,966>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'circleA' A開始初始化 2015-08-01 09:51:34,976>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Eagerly caching bean 'circleA' to allow for resolving potential circular references 2015-08-01 09:51:34,976>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'circleB' 2015-08-01 09:51:34,976>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'circleB' B開始初始化 2015-08-01 09:51:34,976>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Eagerly caching bean 'circleB' to allow for resolving potential circular references 2015-08-01 09:51:34,976>>>>[org.springframework.beans.factory.support.AbstractBeanFactory]-[DEBUG] >>>>Returning eagerly cached instance of singleton bean 'circleA' that is not fully initialized yet - a consequence of a circular reference B開始注入 B完成注入 2015-08-01 09:51:34,986>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Finished creating instance of bean 'circleB' A開始注入 A完成注入 2015-08-01 09:51:34,986>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Finished creating instance of bean 'circleA'
在DefaultSingletonBeanRegistry類中,定義了一些屬性,它決定着整個依賴注入過程的關鍵步驟跳轉,同時也伴隨着整個bean的關鍵週期.
/** 保存全部的singletonBean的實例 */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64); /** singletonBean的生產工廠*/ private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16); /** 保存全部早期建立的Bean對象,這個Bean尚未完成依賴注入 */ private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16); /** 保存全部已經完成初始化的Bean的名字(name) */ private final Set<String> registeredSingletons = new LinkedHashSet<String>(64); /** 標識指定name的Bean對象是否處於建立狀態 這個狀態很是重要 */ private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(16));
singleton的建立開始於getBean方法,關於這個流程,能夠查看另一篇博客。這個方法調用了doGetBean方法,也是示意圖中最頂端的方法,這是建立singleton的開始。
整個過程的源碼不少,這裏僅截取與singleton建立相關的部分
(1)圖中1號代碼getSingleton
protected Object getSingleton(String beanName, boolean allowEarlyReference) { //在已經完成建立的singleton集合中查找 Object singletonObject = this.singletonObjects.get(beanName); //若是沒有找到 而且還處於當前建立狀態,就應該能夠找到earlyReference if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName);//在earlyReference查找 if (singletonObject == null && allowEarlyReference) { //若是尚未找到,就去找對應的工廠方法,這裏與9號代碼迴應。 //若是建立了空的Bean的話,在此處必定能拿到對應的工廠 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject();//在這得到對應的earlyBean this.earlySingletonObjects.put(beanName, singletonObject);//放入earlyBeanObjects集合中 this.singletonFactories.remove(beanName);//移除工廠方法 } } } } return (singletonObject != NULL_OBJECT ? singletonObject : null); }
// Eagerly check singleton cache for manually registered singletons. Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { if (logger.isDebugEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.debug("Returning cached instance of singleton bean '" + beanName + "'"); } } bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); }
if (mbd.isSingleton()) { //註冊工廠 調用另外一個getSingleton sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { try { //建立Bean的實際方法 return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { //非空校驗 Assert.notNull(beanName, "'beanName' must not be null"); synchronized (this.singletonObjects) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { if (this.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while the singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); } if (logger.isDebugEnabled()) { logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); } //前置處理 beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<Exception>(); } try { //調用工程方法 singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { // Has the singleton object implicitly appeared in the meantime -> // if yes, proceed with it since the exception indicates that state. singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { throw ex; } } catch (BeanCreationException ex) { if (recordSuppressedExceptions) { for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); } } throw ex; } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } //後置處理 afterSingletonCreation(beanName); } if (newSingleton) { addSingleton(beanName, singletonObject); } } return (singletonObject != NULL_OBJECT ? singletonObject : null); } }
protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } }
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) { //... if (instanceWrapper == null) { //建立Bean的實際方法 instanceWrapper = createBeanInstance(beanName, mbd, args); } //... 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"); } //註冊getEaryBean的工廠方法 addSingletonFactory(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { return getEarlyBeanReference(beanName, mbd, bean); } }); } // Initialize the bean instance. Object exposedObject = bean; try { //開始依賴注入 觸發getBean方法 populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null) { exposedObject = initializeBean(beanName, exposedObject, mbd); } } catch (Throwable ex) { if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { throw (BeanCreationException) ex; } else { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); } } //... return exposedObject; }
(7 )createBeanInstance方法,實際建立Bean的方法
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) { //... // 在這裏去匹配合適的構造方法,若是存在構造注入,須要找到全部的注入的值,觸發getBean Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } // No special handling: simply use no-arg constructor. return instantiateBean(beanName, mbd); }
經過上面的分析,已經基本能夠看出設值注入與構造注入的區別在哪裏,就是觸發getBean遞歸的時機不一致,致使1號的getSingleton的結果不同。
對於設值注入來講,首先進入getA的getBean,此時getSingleton返回null,進入Bean的建立階段,此時採用設值注入,構造默認的空的Bean,並註冊一個工廠方法,而後依賴注入,getBean的時候觸發了對B的構造過程,與A同樣,構造默認的空的Bean,並註冊一個工廠方法,而後依賴注入,這時須要A,第二次進入A的getBean流程,而此時由於存在工廠方法,因此1號的getSingleton再也不返回空,這樣就返回了一個Earlybean對象注入到B中;而後B完成注入,接着A完成注入。
對於構造注入來講,首先進入getA的getBean,此時getSingleton返回null,進入Bean的建立階段,此時採用構造注入,在查找注入參數的時候,就觸發了B的getBean方法,注意此時並無註冊工廠方法,B的建立流程開始,採用構造注入,查找注入參數,第二次進入A的getBean方法,由於沒有提供能夠拿到earlyBean的工廠方法,1號getSingleton將返回空,此時將再次進入紅色方法區,再次調用4號方法時,就會拋出重複建立的異常。
對於混合方式來講,由於其中之一採用設值注入,再第二個進入這個對象的getBean方法的時候,總會獲得earlyBean,所以不會拋出異常,也就能夠完成建立。
在此能夠得出結論,Spring對於循環引用的解決方案就是暴露一個ObjectFactroy,對於未建立完成的Bean,能夠經過這個工廠獲得一個earlyBean保證「鎖」被釋放,完成流程。而能夠暴露這個ObjectFactory的惟一條件就是必須採用設值注入,以保證能夠提早構造一個空的earlyBean。
相對於singleton來講,prototype就簡單的多,因爲方法名都相似,在這直接給出整個流程的代碼。
(1) 關鍵屬性 只有一個,保存着正在建立的prototype的beanName
/** Names of beans that are currently in creation */ private final ThreadLocal<Object> prototypesCurrentlyInCreation = new NamedThreadLocal<Object>("Prototype beans currently in creation");
//流程1 檢驗當前的bean是否處於 // Fail if we're already creating this bean instance: // We're assumably within a circular reference. if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } //流程2 建立Bean else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. Object prototypeInstance = null; try { //前置處理 beforePrototypeCreation(beanName); //建立流程的開始 prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); }
前置處理看着挺複雜,其實就是把每一個正在建立的prototype的BeanName放入一個set中
protected void beforePrototypeCreation(String beanName) { Object curVal = this.prototypesCurrentlyInCreation.get(); if (curVal == null) { this.prototypesCurrentlyInCreation.set(beanName); } else if (curVal instanceof String) { Set<String> beanNameSet = new HashSet<String>(2); beanNameSet.add((String) curVal); beanNameSet.add(beanName); this.prototypesCurrentlyInCreation.set(beanNameSet); } else { Set<String> beanNameSet = (Set<String>) curVal; beanNameSet.add(beanName); } }
protected boolean isPrototypeCurrentlyInCreation(String beanName) { Object curVal = this.prototypesCurrentlyInCreation.get(); return (curVal != null && (curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName)))); }
從流程上就能夠查看,不管是構造注入仍是設值注入,第二次進入同一個Bean的getBean方法是,必定會在校驗部分拋出異常,所以不能完成注入,也就不能實現循環引用。