spring如何解決單例循環依賴問題?

更多文章點擊--spring源碼分析系列html

 

一、spring循環依賴場景
二、循環依賴解決方式: 三級緩存java

 

一、spring循環引用場景spring

循環依賴的產生可能有不少種狀況,例如:緩存

  • A的構造方法中依賴了B的實例對象,同時B的構造方法中依賴了A的實例對象
  • A的構造方法中依賴了B的實例對象,同時B的某個field或者setter須要A的實例對象,以及反之
  • A的某個field或者setter依賴了B的實例對象,同時B的某個field或者setter依賴了A的實例對象,以及反之

Spring對於循環依賴的解決不是無條件的,首先前提條件是針對scope單例而且容許解決循環依賴的對象。以上三種狀況: 第一種Spring沒法解決, 第二種只能解決一部分狀況, 第三種能夠解決app

如下爲對應的示例demo:ide

 1 public class CirculationA {  2 
 3     private CirculationB circulationB;  4 
 5     public CirculationA(CirculationB circulationB) {  6         this.circulationB = circulationB;  7  }  8 
 9     public CirculationA() { 10  } 11 
12     public CirculationB getCirculationB() { 13         return circulationB; 14  } 15 
16     public void setCirculationB(CirculationB circulationB) { 17         this.circulationB = circulationB; 18  } 19 } 20 
21 public class CirculationB { 22     private CirculationA circulationA; 23 
24     public CirculationB(CirculationA circulationA) { 25         this.circulationA = circulationA; 26  } 27     public CirculationB() { 28  } 29 
30     public CirculationA getCirculationA() { 31         return circulationA; 32  } 33 
34     public void setCirculationA(CirculationA circulationA) { 35         this.circulationA = circulationA; 36  } 37 }
pojo.java

 ioc-CirculationReference.xml函數

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
   <!--使用構造函數互相引用 -->
    <bean id="circulationb" class="com.nancy.ioc.CirculationReference.CirculationB" >
        <constructor-arg name="circulationA" ref="circulationa"/>
    </bean>
    <bean id="circulationa" class="com.nancy.ioc.CirculationReference.CirculationA" >
        <constructor-arg name="circulationB" ref="circulationb"/>
    </bean>
</beans>

CirculationReferenceTest代碼源碼分析

 1 public class CirculationReferenceTest {  2     private ApplicationContext applicationContext ;  3 
 4  @Before  5     public void beforeApplicationContext(){  6         applicationContext = new ClassPathXmlApplicationContext("ioc-CirculationReference.xml") ;  7  }  8 
 9  @Test 10     public void test(){ 11 
12  } 13 
14  @After 15     public void after(){ 16         if(applicationContext != null){ 17  ((ClassPathXmlApplicationContext)applicationContext).close(); 18  } 19  } 20 }
CirculationReferenceTest.java

 錯誤堆棧信息: 驗證了spring沒法解決第一種循環依賴ui

 1 org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'circulationb' defined in class path resource [ioc-CirculationReference.xml]: Cannot resolve reference to bean 'circulationa' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'circulationa' defined in class path resource [ioc-CirculationReference.xml]: Cannot resolve reference to bean 'circulationb' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'circulationb': Requested bean is currently in creation: Is there an unresolvable circular reference?
 2 
 3     at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:378)  4     at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:110)  5     at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:676)  6     at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:188)  7     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1308)  8     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1154)  9     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538) 10     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498) 11     at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) 12     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) 13     at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) 14     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) 15     at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:846) 16     at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:863) 17     at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546) 18     at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:144) 19     at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:85) 20     at com.nancy.ioc.CirculationReferenceTest.beforeApplicationContext(CirculationReferenceTest.java:18) 21  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 22     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 23     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 24     at java.lang.reflect.Method.invoke(Method.java:498) 25     at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) 26     at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 27     at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) 28     at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24) 29     at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) 30     at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) 31     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) 32     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) 33     at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 34     at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 35     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 36     at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 37     at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 38     at org.junit.runners.ParentRunner.run(ParentRunner.java:363) 39     at org.junit.runner.JUnitCore.run(JUnitCore.java:137) 40     at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) 41     at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) 42     at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) 43     at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) 44 Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'circulationa' defined in class path resource [ioc-CirculationReference.xml]: Cannot resolve reference to bean 'circulationb' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'circulationb': Requested bean is currently in creation: Is there an unresolvable circular reference?
45     at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:378) 46     at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:110) 47     at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:676) 48     at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:188) 49     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1308) 50     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1154) 51     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538) 52     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498) 53     at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) 54     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) 55     at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) 56     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) 57     at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:367) 58     ... 40 more 59 Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'circulationb': Requested bean is currently in creation: Is there an unresolvable circular reference?
60     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.beforeSingletonCreation(DefaultSingletonBeanRegistry.java:339) 61     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:215) 62     at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) 63     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) 64     at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:367) 65     ... 52 more

 

 修改對應的ioc-CirculationReference.xml以下並再次運行:  驗證第二種狀況, 此時運行結果正常. this

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    <!-- B的filed依賴A  A構造函數依賴B -->
    <bean id="circulationb" class="com.nancy.ioc.CirculationReference.CirculationB" >
        <property name="circulationA" ref="circulationa"/>
    </bean>
    <bean id="circulationa" class="com.nancy.ioc.CirculationReference.CirculationA" >
        <constructor-arg name="circulationB" ref="circulationb"/>
    </bean>
</beans>

 若是將 circulationa 和 circulationb 在ioc-CirculationReference.xml文件聲明的順序調換, 使用構造的circulationa先加載.  再次報循環依賴沒法解析 爲何會出現這樣的狀況呢?

 

二、循環依賴解決方式: 三級緩存

第一個demo標紅的錯誤堆棧部分信息清晰的看出bean建立基本流程, 由refresh()爲入口切入, 這裏只分析單例bean建立流程: 

1)、AbstractBeanFactory.getBean爲入口 並委託 AbstractBeanFactory.doGetBean建立
2)、AbstractBeanFactory.doGetBean 會首先從AbstractBeanFactory.getSingleton中獲取緩存的bean對象, 若是不存在則調用抽象方法createBean, 即子類實現的AbstractAutowireCapableBeanFactory.createBean方法
3)、AbstractAutowireCapableBeanFactory.createBean方法觸發doCreateBean依次調用如下方法實現bean建立過程

  • createBeanInstance: 實例化bean, 若是須要依賴其餘對象則首先建立其餘對象(發生循環依賴的地方)
  • addSingletonFactory: 將實例化bean加入三級緩存
  • populateBean: 初始化bean, 若是須要依賴其餘對象則首先建立其餘對象(發生循環依賴的地方)
  • initializeBean
  • registerDisposableBeanIfNecessary

4)、AbstractAutowireCapableBeanFactory.autowireConstructor使用構造函數進行實例化

5)、最終調用 ConstructorResolver.autowireConstructor 和 ConstructorResolver.resolveConstructorArguments 進行實例化已經解析構造參數

6)、調用BeanDefinitionValueResolver.resolveValueIfNecessary 和 BeanDefinitionValueResolver.resolveReference 模版類解析構造參數

 

這裏只分析流程主幹代碼:

 AbstractBeanFactory爲bean建立的入口

 1 @Override  2     public Object getBean(String name) throws BeansException {  3         return doGetBean(name, null, null, false);  4  }  5 
 6 protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,  7             @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {  8 
 9         final String beanName = transformedBeanName(name); 10  Object bean; 11 
12         // Eagerly check singleton cache for manually registered singletons. 13         //  
14         Object sharedInstance = getSingleton(beanName); 15         if (sharedInstance != null && args == null) { 16             if (logger.isTraceEnabled()) { 17                 if (isSingletonCurrentlyInCreation(beanName)) { 18                     logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
19                             "' that is not fully initialized yet - a consequence of a circular reference"); 20  } 21                 else { 22                     logger.trace("Returning cached instance of singleton bean '" + beanName + "'"); 23  } 24  } 25             bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); 26  } 27 
28         else { 29             // Fail if we're already creating this bean instance: 30             // We're assumably within a circular reference.
31             if (isPrototypeCurrentlyInCreation(beanName)) { 32                 throw new BeanCurrentlyInCreationException(beanName); 33  } 34 
35             //......省略...... 36             //......省略......
37 
38             try { 39             //......省略...... 40 
41                 // Create bean instance.
42                 if (mbd.isSingleton()) { 43                     sharedInstance = getSingleton(beanName, () -> { 44                         try { 45                             return createBean(beanName, mbd, args); 46  } 47                         catch (BeansException ex) { 48                             // Explicitly remove instance from singleton cache: It might have been put there 49                             // eagerly by the creation process, to allow for circular reference resolution. 50                             // Also remove any beans that received a temporary reference to the bean.
51  destroySingleton(beanName); 52                             throw ex; 53  } 54  }); 55                     bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 56  } 57 
58               //........
59  } 60 
61 
62     protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) 63             throws BeanCreationException;
AbstractBeanFactory.java

在DefaultSingletonBeanRegistry使用三級緩存:

// 第一層: 初始化完備的單例bean /** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); // 第二層: 提早暴光的單例對象的Cache  /** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); // 第三層: ObjectFactory工廠bean緩存, 存儲實例話後的bean Factory /** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

從緩存中獲取單例對象

 1  protected Object getSingleton(String beanName, boolean allowEarlyReference) {  2         // 首先從第一層緩存獲取
 3         Object singletonObject = this.singletonObjects.get(beanName);  4         // 其次第一層未找到緩存 且 bean處於建立中(例如A定義的構造函數依賴了B對象,得先去建立B對象,或者在populatebean過程當中依賴了B對象,得先去建立B對象,此時A處於建立中)
 5         if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {  6             synchronized (this.singletonObjects) {  7                 singletonObject = this.earlySingletonObjects.get(beanName);  8                 // 最後第二層未找到緩存 並 容許循環依賴即從工廠類獲取對象
 9                 if (singletonObject == null && allowEarlyReference) { 10                     ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); 11                     if (singletonFactory != null) { 12                         singletonObject = singletonFactory.getObject(); 13                         // 此時會將三級緩存 移入 二級緩存
14                         this.earlySingletonObjects.put(beanName, singletonObject); 15                         this.singletonFactories.remove(beanName); 16  } 17  } 18  } 19  } 20         return (singletonObject != NULL_OBJECT ? singletonObject : null); 21     }
getSingleton(String beanName, boolean allowEarlyReference)

 建立並緩存單例對象: 建立過程當中會暫時先標記bean爲建立中, 建立完成以後會清楚該標記並加入第一級緩存

// 建立並註冊單例對象 若是存在直接返回
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name 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 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 + "'"); } // 標記建立開始, 用於標記建立中 屢次建立會拋出BeanCurrentlyInCreationException
 beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } 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; } }
getSingleton(String beanName, ObjectFactory<?> singletonFactory)

標記函數, 重複操做會拋出異常, 循環依賴不能解析拋出異常的觸發點

 1 /**
 2  * Callback before singleton creation.  3  * <p>The default implementation register the singleton as currently in creation.  4  * @param beanName the name of the singleton about to be created  5  * @see #isSingletonCurrentlyInCreation  6      */
 7     protected void beforeSingletonCreation(String beanName) {  8         if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {  9             throw new BeanCurrentlyInCreationException(beanName); 10  } 11  } 12 
13     /**
14  * Callback after singleton creation. 15  * <p>The default implementation marks the singleton as not in creation anymore. 16  * @param beanName the name of the singleton that has been created 17  * @see #isSingletonCurrentlyInCreation 18      */
19     protected void afterSingletonCreation(String beanName) { 20         if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) { 21             throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation"); 22  } 23     }
標記和清除bean處於建立中方法

 AbstractAutowireCapableBeanFactory中doCreateBean: 核心createBeanInstance、addSingletonFactory、populateBean

 1 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)  2             throws BeanCreationException {  3 
 4         // Instantiate the bean.
 5         BeanWrapper instanceWrapper = null;  6         if (mbd.isSingleton()) {  7             instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);  8  }  9         // 建立bean實例化, 此時bean並未進行
10         if (instanceWrapper == null) { 11             instanceWrapper = createBeanInstance(beanName, mbd, args); 12  } 13         //......... 14 
15         // bean爲單例並 容許循環依賴 且 處於建立中 加入3級緩存 16         // Eagerly cache singletons to be able to resolve circular references 17         // even when triggered by lifecycle interfaces like BeanFactoryAware.
18         boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
19  isSingletonCurrentlyInCreation(beanName)); 20         if (earlySingletonExposure) { 21             if (logger.isTraceEnabled()) { 22                 logger.trace("Eagerly caching bean '" + beanName +
23                         "' to allow for resolving potential circular references"); 24  } 25             addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); 26  } 27 
28         // Initialize the bean instance.
29         Object exposedObject = bean; 30         try { 31             // 對bean屬性進行復制
32  populateBean(beanName, mbd, instanceWrapper); 33             // 調用初始化方法
34             exposedObject = initializeBean(beanName, exposedObject, mbd); 35  } 36         catch (Throwable ex) { 37             if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { 38                 throw (BeanCreationException) ex; 39  } 40             else { 41                 throw new BeanCreationException( 42                         mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); 43  } 44  } 45 
46         if (earlySingletonExposure) { 47             Object earlySingletonReference = getSingleton(beanName, false); 48             if (earlySingletonReference != null) { 49                 if (exposedObject == bean) { 50                     exposedObject = earlySingletonReference; 51  } 52                 else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { 53                     String[] dependentBeans = getDependentBeans(beanName); 54                     Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length); 55                     for (String dependentBean : dependentBeans) { 56                         if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { 57  actualDependentBeans.add(dependentBean); 58  } 59  } 60                     if (!actualDependentBeans.isEmpty()) { 61                         throw new BeanCurrentlyInCreationException(beanName, 62                                 "Bean with name '" + beanName + "' has been injected into other beans [" +
63                                 StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
64                                 "] in its raw version as part of a circular reference, but has eventually been " +
65                                 "wrapped. This means that said other beans do not use the final version of the " +
66                                 "bean. This is often the result of over-eager type matching - consider using " +
67                                 "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."); 68  } 69  } 70  } 71  } 72 
73         // Register bean as disposable.
74         try { 75  registerDisposableBeanIfNecessary(beanName, bean, mbd); 76  } 77         catch (BeanDefinitionValidationException ex) { 78             throw new BeanCreationException( 79                     mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); 80  } 81 
82         return exposedObject; 83  } 84 
85 protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { 86     Assert.notNull(singletonFactory, "Singleton factory must not be null"); 87     synchronized (this.singletonObjects) { 88         if (!this.singletonObjects.containsKey(beanName)) { 89             this.singletonFactories.put(beanName, singletonFactory); 90             this.earlySingletonObjects.remove(beanName); 91             this.registeredSingletons.add(beanName); 92  } 93  } 94 }
View Code

 ConstructorResolver

public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) { // ........

            int minNrOfArgs; if (explicitArgs != null) { minNrOfArgs = explicitArgs.length; } else { ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues(); resolvedValues = new ConstructorArgumentValues(); minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); } // ........
} private int resolveConstructorArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw, ConstructorArgumentValues cargs, ConstructorArgumentValues resolvedValues) { //.......

        for (ConstructorArgumentValues.ValueHolder valueHolder : cargs.getGenericArgumentValues()) { if (valueHolder.isConverted()) { resolvedValues.addGenericArgumentValue(valueHolder); } else { Object resolvedValue = valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue()); ConstructorArgumentValues.ValueHolder resolvedValueHolder = new ConstructorArgumentValues.ValueHolder( resolvedValue, valueHolder.getType(), valueHolder.getName()); resolvedValueHolder.setSource(valueHolder); resolvedValues.addGenericArgumentValue(resolvedValueHolder); } } return minNrOfArgs; }
ConstructorResolver.java

BeanDefinitionValueResolver

 1 @Nullable  2     public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {  3         // We must check each value to see whether it requires a runtime reference  4         // to another bean to be resolved.
 5         if (value instanceof RuntimeBeanReference) {  6             RuntimeBeanReference ref = (RuntimeBeanReference) value;  7             return resolveReference(argName, ref);  8  }  9         //.......
10  } 11 
12  @Nullable 13     private Object resolveReference(Object argName, RuntimeBeanReference ref) { 14         try { 15  Object bean; 16             String refName = ref.getBeanName(); 17             refName = String.valueOf(doEvaluate(refName)); 18             if (ref.isToParent()) { 19                 if (this.beanFactory.getParentBeanFactory() == null) { 20                     throw new BeanCreationException( 21                             this.beanDefinition.getResourceDescription(), this.beanName, 22                             "Can't resolve reference to bean '" + refName +
23                             "' in parent factory: no parent factory available"); 24  } 25                 bean = this.beanFactory.getParentBeanFactory().getBean(refName); 26  } 27             else { 28                 bean = this.beanFactory.getBean(refName); 29                 this.beanFactory.registerDependentBean(refName, this.beanName); 30  } 31             if (bean instanceof NullBean) { 32                 bean = null; 33  } 34             return bean; 35  } 36         catch (BeansException ex) { 37             throw new BeanCreationException( 38                     this.beanDefinition.getResourceDescription(), this.beanName, 39                     "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex); 40  } 41     }
BeanDefinitionValueResolver.java

 

 首先須要明確spring對象若是拿不到構造參數將沒法使用構造函數實例化,  因此若是構造函數依賴於其餘對象必然先去建立其餘對象. 若是是使用默認空參構造則能夠實例化, 若是初始化階段依賴於其餘對象必然會去建立其餘對象. 

  • 第一個demo狀況, 當createBeanInstance使用構造函數建立circulationA須要依賴circulationB, 則會暫時停下來並會建立circulationB 並因爲對應未建立並不會加入三級緩存.  當使用構造函數建立circulationB須要依賴circulationA, 則也會暫時停下來並會建立circulationA 並因爲對應未建立並不會加入三級緩存. 當建立circulationA會再次調用beforeSingletonCreation進行標記, 由於會拋出BeanCurrentlyInCreationException異常終止ioc容器初始化. circulationA和circulationB 因爲各自拿不到對應的構造函數參數而沒法實例化
  • 第二個demo狀況, circulationB使用setter依賴circulationA, 所以createBeanInstance使用默認的空參數構造實例化, 完成以後加入三級緩存並在populateBean中屬性進行初始化, 此時須要實例化circulationA.  當使用構造函數建立circulationA須要依賴circulationB, 則也會暫時停下來並去建立circulationB, 因爲在緩存中拿到circulationB即完成circulationA實例化. 再次返回circulationB的populateBean方法. 此時circulationA 和 circulationB 加載完成.  由此能夠類推, 若是隻是經過屬性 或者 setter方法進行循環依賴 spring能夠完美解決. 
  • 在第二個demo狀況中將  circulationB 和  circulationA 聲明順序進行交換依然致使了加載錯誤. 根源問題在於與第一種狀況同樣, circulationA拿不到對應的構造函數參數而沒法實例化 未進入三級緩存, 故而致使了circulationB再次建立circulationA的時候, 由beforeSingletonCreation拋出BeanCurrentlyInCreationException異常終止ioc容器初始化. 

所以得出結果spring解決的循環依賴只是部分, 而沒法解決的狀況是在使用構造函數互相引用的場景. spring bean聲明中應避免第一種狀況 和 第一種狀況的變種狀況. 

 

參考連接:

Spring源碼初探-IOC(4)-Bean的初始化-循環依賴的解決
Spring-bean的循環依賴以及解決方式

相關文章
相關標籤/搜索