1、spring循环引用场景
循环依赖的产生可能有很多种情况,例如:
A的构造方法中依赖了B的实例对象,同时B的构造方法中依赖了A的实例对象
A的构造方法中依赖了B的实例对象,同时B的某个field或者setter需要A的实例对象,以及反之
A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象,以及反之
Spring对于循环依赖的解决不是无条件的,首先前提条件是针对scope单例并且允许解决循环依赖的对象。以上三种情况: 第一种Spring无法解决, 第二种只能解决一部分情况, 第三种可以解决
以下为对应的示例demo:
1 public classCirculationA {2
3 privateCirculationB circulationB;4
5 publicCirculationA(CirculationB circulationB) {6 this.circulationB =circulationB;7 }8
9 publicCirculationA() {10 }11
12 publicCirculationB getCirculationB() {13 returncirculationB;14 }15
16 public voidsetCirculationB(CirculationB circulationB) {17 this.circulationB =circulationB;18 }19 }20
21 public classCirculationB {22 privateCirculationA circulationA;23
24 publicCirculationB(CirculationA circulationA) {25 this.circulationA =circulationA;26 }27 publicCirculationB() {28 }29
30 publicCirculationA getCirculationA() {31 returncirculationA;32 }33
34 public voidsetCirculationA(CirculationA circulationA) {35 this.circulationA =circulationA;36 }37 }
pojo.java
ioc-CirculationReference.xml
CirculationReferenceTest代码
1 public classCirculationReferenceTest {2 privateApplicationContext applicationContext ;3
4 @Before5 public voidbeforeApplicationContext(){6 applicationContext = new ClassPathXmlApplicationContext("ioc-CirculationReference.xml") ;7 }8
9 @Test10 public voidtest(){11
12 }13
14 @After15 public voidafter(){16 if(applicationContext != null){17 ((ClassPathXmlApplicationContext)applicationContext).close();18 }19 }20 }
CirculationReferenceTest.java
错误堆栈信息: 验证了spring无法解决第一种循环依赖
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.(ClassPathXmlApplicationContext.java:144)19 at org.springframework.context.support.ClassPathXmlApplicationContext.(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 ... 40more59 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如下并再次运行: 验证第二种情况, 此时运行结果正常.
如果将 circulationa 和 circulationb 在ioc-CirculationReference.xml文件声明的顺序调换, 使用构造的circulationa先加载.再次报循环依赖无法解析 为什么会出现这样的情况呢?
2、循环依赖解决方式: 三级缓存
第一个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 @Override2 public Object getBean(String name) throwsBeansException {3 return doGetBean(name, null, null, false);4 }5
6 protected T doGetBean(final String name, @Nullable final ClassrequiredType,7 @Nullable final Object[] args, boolean typeCheckOnly) throwsBeansException {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 newBeanCurrentlyInCreationException(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 returncreateBean(beanName, mbd, args);46 }47 catch(BeansException ex) {48 //Explicitly remove instance from singleton cache: It might have been put there49 //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 throwex;53 }54 });55 bean =getObjectForBeanInstance(sharedInstance, name, beanName, mbd);56 }57
58 //........
59 }60
61
62 protected abstractObject 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 singletonObjects = new ConcurrentHashMap<>(256);//第二层: 提前暴光的单例对象的Cache/**Cache of early singleton objects: bean name to bean instance.*/
private final Map earlySingletonObjects = new HashMap<>(16);//第三层: ObjectFactory工厂bean缓存, 存储实例话后的bean Factory/**Cache of singleton factories: bean name to ObjectFactory.*/
private final Map> singletonFactories = new HashMap<>(16);
从缓存中获取单例对象
1 protected Object getSingleton(String beanName, booleanallowEarlyReference) {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 singletnotallow= this.singletonObjects.get(beanName);if (singletonObject == null) {if (this.singletonsCurrentlyInDestruction) {throw newBeanCreationNotAllowedException(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();
newSingletnotallow= 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) {throwex;
}
}catch(BeanCreationException ex) {if(recordSuppressedExceptions) {for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}throwex;
}finally{if(recordSuppressedExceptions) {this.suppressedExceptions = null;
}//标记创建结束
afterSingletonCreation(beanName);
}//保存入一级缓存 并 清空其他缓存
if(newSingleton) {
addSingleton(beanName, singletonObject);
}
}returnsingletonObject;
}
}
getSingleton(String beanName, ObjectFactory> singletonFactory)
标记函数, 重复操作会抛出异常, 循环依赖不能解析抛出异常的触发点
1 /**
2 * Callback before singleton creation.3 *
The default implementation register the singleton as currently in creation.4 *@parambeanName the name of the singleton about to be created5 *@see#isSingletonCurrentlyInCreation6 */
7 protected voidbeforeSingletonCreation(String beanName) {8 if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {9 throw newBeanCurrentlyInCreationException(beanName);10 }11 }12
13 /**
14 * Callback after singleton creation.15 *
The default implementation marks the singleton as not in creation anymore.16 *@parambeanName the name of the singleton that has been created17 *@see#isSingletonCurrentlyInCreation18 */
19 protected voidafterSingletonCreation(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 throwsBeanCreationException {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 references17 //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 newBeanCreationException(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 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 newBeanCurrentlyInCreationException(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 newBeanCreationException(79 mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);80 }81
82 returnexposedObject;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
publicBeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
@Nullable Constructor>[] chosenCtors, @Nullable Object[] explicitArgs) {//........
intminNrOfArgs;if (explicitArgs != null) {
minNrOfArgs=explicitArgs.length;
}else{
ConstructorArgumentValues cargs=mbd.getConstructorArgumentValues();
resolvedValues= newConstructorArgumentValues();
minNrOfArgs=resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}//........
}private intresolveConstructorArguments(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= newConstructorArgumentValues.ValueHolder(
resolvedValue, valueHolder.getType(), valueHolder.getName());
resolvedValueHolder.setSource(valueHolder);
resolvedValues.addGenericArgumentValue(resolvedValueHolder);
}
}returnminNrOfArgs;
}
ConstructorResolver.java
BeanDefinitionValueResolver
1 @Nullable2 publicObject resolveValueIfNecessary(Object argName, @Nullable Object value) {3 //We must check each value to see whether it requires a runtime reference4 //to another bean to be resolved.
5 if (value instanceofRuntimeBeanReference) {6 RuntimeBeanReference ref =(RuntimeBeanReference) value;7 returnresolveReference(argName, ref);8 }9 //.......
10 }11
12 @Nullable13 privateObject 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 newBeanCreationException(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 instanceofNullBean) {32 bean = null;33 }34 returnbean;35 }36 catch(BeansException ex) {37 throw newBeanCreationException(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声明中应避免第一种情况 和 第一种情况的变种情况.