java循环依赖问题怎么解决_spring如何解决单例循环依赖问题?

1、spring循环引用场景

循环依赖的产生可能有很多种情况,例如:

A的构造方法中依赖了B的实例对象,同时B的构造方法中依赖了A的实例对象

A的构造方法中依赖了B的实例对象,同时B的某个field或者setter需要A的实例对象,以及反之

A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象,以及反之

Spring对于循环依赖的解决不是无条件的,首先前提条件是针对scope单例并且允许解决循环依赖的对象。以上三种情况: 第一种Spring无法解决, 第二种只能解决一部分情况, 第三种可以解决

以下为对应的示例demo:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

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代码

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

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创建的入口

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

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);

从缓存中获取单例对象

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

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为创建中, 创建完成之后会清楚该标记并加入第一级缓存

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

//创建并注册单例对象 如果存在直接返回

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 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();

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) {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)

标记函数, 重复操作会抛出异常, 循环依赖不能解析抛出异常的触发点

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

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声明中应避免第一种情况 和 第一种情况的变种情况.

参考链接:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值