一、spring循環依賴場景
二、循環依賴解決方式: 三級緩存java
循環依賴的產生可能有不少種狀況,例如:緩存
- A的構造方法中依賴了B的實例對象,同時B的構造方法中依賴了A的實例對象
- A的構造方法中依賴了B的實例對象,同時B的某個field或者setter須要A的實例對象,以及反之
- A的某個field或者setter依賴了B的實例對象,同時B的某個field或者setter依賴了A的實例對象,以及反之
Spring對於循環依賴的解決不是無條件的,首先前提條件是針對scope單例而且容許解決循環依賴的對象。以上三種狀況: 第一種Spring沒法解決, 第二種只能解決一部分狀況, 第三種能夠解決app
如下爲對應的示例demo:ide
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
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 }
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代碼源碼分析
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
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 }
錯誤堆棧信息: 驗證了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建立的入口
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
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;
在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);
從緩存中獲取單例對象
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
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 }
建立並緩存單例對象: 建立過程當中會暫時先標記bean爲建立中, 建立完成以後會清楚該標記並加入第一級緩存
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
// 建立並註冊單例對象 若是存在直接返回 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; } }
標記函數, 重複操做會拋出異常, 循環依賴不能解析拋出異常的觸發點
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
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 }
AbstractAutowireCapableBeanFactory中doCreateBean: 核心createBeanInstance、addSingletonFactory、populateBean
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
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 }
ConstructorResolver
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
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; }
BeanDefinitionValueResolver
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
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 }
首先須要明確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聲明中應避免第一種狀況 和 第一種狀況的變種狀況.
參考連接: