junit依赖_Spring容器的循环依赖

看完这一篇文章如果你还不懂循环依赖,那只有葵花宝典可以救你了 上一篇文章剖析了下bean的加载流程,如果你认真看并且自己debug了一遍源码,那么我相信你应该对bean的加载流程有了大致的了解,但是因为篇幅问题,有一个重点没有写到,那就是spring容器的循环依赖,都说这玩意难,今天咱就看看它到底难在哪。 spring容器的循环依赖包括构造器循环依赖和setter循环依赖。 一、首先看下构造器的循环依赖,上代码:1.先定义三个实体类,这三个实体类有个特点,就是第TestA依赖TestB,TestB依赖TestC,TestC依赖TestA
package org.springframework.beans.factory.myspring.circle;/** * @Authror ayo * @Date 2020/11/21 20:10 */public class TestA {  private TestB testB;    public TestA(TestB testB) {    this.testB = testB;  }}
package org.springframework.beans.factory.myspring.circle;/** * @Authror ayo * @Date 2020/11/21 20:10 */public class TestB {  private TestC testC;  public TestB(TestC testC) {    this.testC = testC;  }}
package org.springframework.beans.factory.myspring.circle;/** * @Authror ayo * @Date 2020/11/21 20:11 */public class TestC {  private TestA testA;  public TestC(TestA testA) {    this.testA = testA;  }}
2.添加配置文件
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">      <bean id="testA" class="org.springframework.beans.factory.myspring.circle.TestA">        <constructor-arg index="0" ref="testB">constructor-arg>  bean>  <bean id="testB" class="org.springframework.beans.factory.myspring.circle.TestB">    <constructor-arg index="0" ref="testC">constructor-arg>  bean>  <bean id="testC" class="org.springframework.beans.factory.myspring.circle.TestC">    <constructor-arg index="0" ref="testA">constructor-arg>  bean>beans>
3.写个测试类
package org.springframework.beans.factory.myspring;import org.junit.Test;import org.junit.rules.ExpectedException;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.BeanCurrentlyInCreationException;import org.springframework.beans.factory.BeanFactory;import org.springframework.beans.factory.myspring.circle.TestA;import org.springframework.beans.factory.xml.XmlBeanFactory;import org.springframework.core.io.ClassPathResource;/** * @Authror ayo * @Date 2020/11/16 17:52 */public class BeanFactoryTest {  private static final Logger logger = LoggerFactory.getLogger(BeanFactoryTest.class);  /**   * 测试构造器的循环依赖   */  @Test  public void testCircleByConstructor() {    try {      XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("org/springframework/beans/factory/myspring/beanFactoryTest.xml"));      xmlBeanFactory.getBean("testA");    }catch (Exception e){      logger.error("testCircleByConstructor error==>" + e.getMessage(), e);    }  }}
首先运行下看看

31b09e7c5603c589d35746eb76abcb47.png

报错了,看下异常信息
21:13:55.057 [main] ERROR org.springframework.beans.factory.myspring.BeanFactoryTest - testCircleByConstructor error==>Error creating bean with name 'testA' defined in class path resource [org/springframework/beans/factory/myspring/beanFactoryTest.xml]: Cannot resolve reference to bean 'testB' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testB' defined in class path resource [org/springframework/beans/factory/myspring/beanFactoryTest.xml]: Cannot resolve reference to bean 'testC' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testC' defined in class path resource [org/springframework/beans/factory/myspring/beanFactoryTest.xml]: Cannot resolve reference to bean 'testA' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'testA': Requested bean is currently in creation: Is there an unresolvable circular reference?org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testA' defined in class path resource [org/springframework/beans/factory/myspring/beanFactoryTest.xml]: Cannot resolve reference to bean 'testB' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testB' defined in class path resource [org/springframework/beans/factory/myspring/beanFactoryTest.xml]: Cannot resolve reference to bean 'testC' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testC' defined in class path resource [org/springframework/beans/factory/myspring/beanFactoryTest.xml]: Cannot resolve reference to bean 'testA' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'testA': Requested bean is currently in creation: Is there an unresolvable circular reference?  at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:314) ~[classes/:?]  at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:110) ~[classes/:?]  at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:626) ~[classes/:?]  at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:154) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1266) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1123) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:535) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:319) ~[classes/:?]  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:235) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:317) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:201) ~[classes/:?]  at org.springframework.beans.factory.myspring.BeanFactoryTest.testCircleByConstructor(BeanFactoryTest.java:39) [classes/:?]  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_181]  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_181]  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_181]  at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_181]  at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) [junit-4.12.jar:4.12]  at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) [junit-4.12.jar:4.12]  at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) [junit-4.12.jar:4.12]  at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) [junit-4.12.jar:4.12]  at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) [junit-4.12.jar:4.12]  at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) [junit-4.12.jar:4.12]  at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) [junit-4.12.jar:4.12]  at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) [junit-4.12.jar:4.12]  at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) [junit-4.12.jar:4.12]  at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) [junit-4.12.jar:4.12]  at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) [junit-4.12.jar:4.12]  at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) [junit-4.12.jar:4.12]  at org.junit.runners.ParentRunner.run(ParentRunner.java:363) [junit-4.12.jar:4.12]  at org.junit.runner.JUnitCore.run(JUnitCore.java:137) [junit-4.12.jar:4.12]  at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) [junit-rt.jar:?]  at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) [junit-rt.jar:?]  at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) [junit-rt.jar:?]  at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) [junit-rt.jar:?]Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testB' defined in class path resource [org/springframework/beans/factory/myspring/beanFactoryTest.xml]: Cannot resolve reference to bean 'testC' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testC' defined in class path resource [org/springframework/beans/factory/myspring/beanFactoryTest.xml]: Cannot resolve reference to bean 'testA' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'testA': Requested bean is currently in creation: Is there an unresolvable circular reference?  at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:314) ~[classes/:?]  at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:110) ~[classes/:?]  at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:626) ~[classes/:?]  at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:154) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1266) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1123) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:535) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:319) ~[classes/:?]  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:235) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:317) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:201) ~[classes/:?]  at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:303) ~[classes/:?]  ... 34 moreCaused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testC' defined in class path resource [org/springframework/beans/factory/myspring/beanFactoryTest.xml]: Cannot resolve reference to bean 'testA' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'testA': Requested bean is currently in creation: Is there an unresolvable circular reference?  at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:314) ~[classes/:?]  at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:110) ~[classes/:?]  at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:626) ~[classes/:?]  at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:154) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1266) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1123) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:535) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:319) ~[classes/:?]  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:235) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:317) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:201) ~[classes/:?]  at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:303) ~[classes/:?]  at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:110) ~[classes/:?]  at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:626) ~[classes/:?]  at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:154) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1266) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1123) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:535) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:319) ~[classes/:?]  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:235) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:317) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:201) ~[classes/:?]  at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:303) ~[classes/:?]  ... 34 moreCaused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'testA': Requested bean is currently in creation: Is there an unresolvable circular reference?  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.beforeSingletonCreation(DefaultSingletonBeanRegistry.java:352) ~[classes/:?]  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:317) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:201) ~[classes/:?]  at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:303) ~[classes/:?]  at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:110) ~[classes/:?]  at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:626) ~[classes/:?]  at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:154) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1266) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1123) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:535) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:319) ~[classes/:?]  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:235) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:317) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:201) ~[classes/:?]  at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:303) ~[classes/:?]  at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:110) ~[classes/:?]  at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:626) ~[classes/:?]  at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:154) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1266) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1123) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:535) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:319) ~[classes/:?]  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:235) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:317) ~[classes/:?]  at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:201) ~[classes/:?]  at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:303) ~[classes/:?]  ... 34 more
看异常信息要看Caused by,从上到下代表越来越底层,所以就看最后一个Caused by报的什么:
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'testA': Requested bean is currently in creation: Is there an unresolvable circular reference?  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.beforeSingletonCreation(DefaultSingletonBeanRegistry.java:352) ~[classes/:?]
不了解的小伙伴可以涨点姿势,如果你某一天启动项目的时候发现报了一个这种异常,就说明你的spring容器中发生了循环依赖导致启动失败,为什么?这里面流程有点长,如果我把图放出来不知道要多少张,估计图没放完你们都蒙圈了,所以我整了个视频:视频中的运行流程如下:

56b6a394c65c76da057e8debd47d61b0.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 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 + "'");        }        //关键就在这个方法        /**protected void beforeSingletonCreation(String beanName) {          if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {            throw new BeanCurrentlyInCreationException(beanName);          }}*/        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;    }  }
@Nullable  private Object resolveReference(Object argName, RuntimeBeanReference ref) {    try {      Object bean;      //拿到当前bean依赖的beanName      String refName = ref.getBeanName();      refName = String.valueOf(doEvaluate(refName));      if (ref.isToParent()) {        if (this.beanFactory.getParentBeanFactory() == null) {          throw new BeanCreationException(              this.beanDefinition.getResourceDescription(), this.beanName,              "Can't resolve reference to bean '" + refName +                  "' in parent factory: no parent factory available");        }        bean = this.beanFactory.getParentBeanFactory().getBean(refName);      }      else {        //重新调用getBean来创建依赖的bean        bean = this.beanFactory.getBean(refName);        this.beanFactory.registerDependentBean(refName, this.beanName);      }      if (bean instanceof NullBean) {        bean = null;      }      return bean;    }    catch (BeansException ex) {      throw new BeanCreationException(          this.beanDefinition.getResourceDescription(), this.beanName,          "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);    }  }
1.首次调用AbstractBeanFactory#getBean,运行到!DefaultSingltonBeanRegistry.singletonsCurrentlyInCreation.add(beanName)时,这时候beanName是testA,将testA添加进去。 2.然后运行到BeanDefinitionValueResolver#resolveReference时候,发现testA中依赖testB,看第6行代码,拿到的ref是testB,然后第19行回去创建testB。 3.第二次调用AbstractBeanFactory#getBean,运行到!DefaultSingltonBeanRegistry.singletonsCurrentlyInCreation.add(beanName)时,这时候beanName是testB,将testB添加进去。 4.然后运行到BeanDefinitionValueResolver#resolveReference时候,发现testB中依赖testC,看第6行代码,拿到的ref是testC,然后第19行回去创建testC。 5.第三次调用AbstractBeanFactory#getBean,运行到!DefaultSingltonBeanRegistry.singletonsCurrentlyInCreation.add(beanName)时,这时候beanName是testC,将testC添加进去。 6.然后运行到BeanDefinitionValueResolver#resolveReference时候,发现testC中依赖testA,看第6行代码,拿到的ref是testA,然后第19行回去创建testA。 7.第四次调用AbstractBeanFactory#getBean,运行到!DefaultSingltonBeanRegistry.singletonsCurrentlyInCreation.add(beanName)时,这时候beanName是testA,将testA添加进去,但是!!这时候你会发现添加失败了,为什么?因为testA在第一次走getBean的时候已经被添加进去了,然后程序就抛异常了,循环依赖出现了!!! 通过上面的分析可以得出结论,通过构造器注入的循环依赖,spring容器是无法解决的,只能抛出BeanCurrentlyInCreationException的异常。 二、setter循环依赖, 上代码: 首先三个实体类需要做下修改,原来使用构造器注入,现在使用setter注入:
package org.springframework.beans.factory.myspring.circle;/** * @Authror ayo * @Date 2020/11/21 20:10 */public class TestA {  private TestB testB;  public TestB getTestB() {    return testB;  }  public void setTestB(TestB testB) {    this.testB = testB;  }}
package org.springframework.beans.factory.myspring.circle;/** * @Authror ayo * @Date 2020/11/21 20:10 */public class TestB {  private TestC testC;  public TestC getTestC() {    return testC;  }  public void setTestC(TestC testC) {    this.testC = testC;  }}
package org.springframework.beans.factory.myspring.circle;/** * @Authror ayo * @Date 2020/11/21 20:11 */public class TestC {  private TestA testA;  public TestA getTestA() {    return testA;  }  public void setTestA(TestA testA) {    this.testA = testA;  }}
然后配置文件也做下改动,改成setter注入的配置方式:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">      <bean id="testA" class="org.springframework.beans.factory.myspring.circle.TestA">        <property name="testB" ref="testB"/>  bean>  <bean id="testB" class="org.springframework.beans.factory.myspring.circle.TestB">    <property name="testC" ref="testC"/>  bean>  <bean id="testC" class="org.springframework.beans.factory.myspring.circle.TestC">    <property name="testA" ref="testA"/>  bean>beans>
测试类同样同样也修改下:
package org.springframework.beans.factory.myspring;import org.junit.Test;import org.junit.rules.ExpectedException;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.BeanCurrentlyInCreationException;import org.springframework.beans.factory.BeanFactory;import org.springframework.beans.factory.myspring.circle.TestA;import org.springframework.beans.factory.xml.XmlBeanFactory;import org.springframework.core.io.ClassPathResource;/** * @Authror ayo * @Date 2020/11/16 17:52 */public class BeanFactoryTest {  private static final Logger logger = LoggerFactory.getLogger(BeanFactoryTest.class);    /**   * 测试setter的循环依赖   */  @Test  public void testCircleBySetter() {    try {      XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("org/springframework/beans/factory/myspring/beanFactoryTest.xml"));      TestA testA = (TestA) xmlBeanFactory.getBean("testA");      System.out.println("testA=" + testA);    }catch (Exception e){      logger.error("testCircleByConstructor error==>" + e.getMessage(), e);    }  }}
运行下代码:

0d44263ec846db9dc2583454ca411169.png

哎?怎么green bar了, 说明setter的循环依赖spring可以解决!! 接下来就要分析下spring是怎么解决的,还是先上个视频,因为链路实在是太TM长了,你们主要关注我鼠标点的地方出来的参数就行: 下面我画个流程图来描述下上面视频的流程,你就明白了:

0e079f4f221853777cbf69922bf6778b.png

这个流程和构造器注入的相比要复杂点,下面分析下这个流程,其实主要分析的是三级缓存的变化情况: 1.第一次请求,创建testA,调用DefaultSingletonBeanRegistry#addSingletonFactory完后三级缓存是这样的:

a6a379a3a9bf19defff739a0ddd7bab0.png

2.因为testA中有testB属性,所以去创建testB, 调用 DefaultSingletonBeanRegistry#addSingletonFactory 完 后三级缓存是这样的:

21fd2aec95eff08b3935dcf1e4519a47.png

3.同样因为testB中有testC属性,所以去创建testC,调用DefaultSingletonBeanRegistry#addSingletonFactory完后三级缓存是这样的:

40076fed237c33139f4dd71c37f2fdec.png

4. 同样因为 testC中有testA属性,所以去创建testA, 调用doGetBean方法,关键点来了啊兄弟们:

4726328166cb83da41d4465982516fae.png

前三步骤为什么我没有在这一步进行细说,来,看代码:
@Nullable  protected Object getSingleton(String beanName, boolean allowEarlyReference) {    Object singletonObject = this.singletonObjects.get(beanName);    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {      synchronized (this.singletonObjects) {        singletonObject = this.earlySingletonObjects.get(beanName);        if (singletonObject == null && allowEarlyReference) {          ObjectFactory> singletonFactory = this.singletonFactories.get(beanName);          if (singletonFactory != null) {            singletonObject = singletonFactory.getObject();            this.earlySingletonObjects.put(beanName, singletonObject);            this.singletonFactories.remove(beanName);          }        }      }    }    return singletonObject;  }
你分析下,创建testA,创建testB,创建testC的时候,能拿到sharedInstance吗(就是上面这个方法返回的),肯定拿不到啊,为什么?因为只有bean快创建完后才会放入缓存的啊,也就是说testA,testB,testC创建完后才会放入缓存,这时候testC创建完成了,发现依赖属性testA,然后去注入属性testA,就是又走doGetBean获取testA去了,这时候关键点来了,看下上面的截图,去获取sharedInstance的时候,看下这个缓存中的取值,来个视频: 看见没,其实是从singletonFactories这个缓存中获取到了创建这个bean的工厂,然后走AbstractBeanFactory#getObjectForBeanInstance方法去获取testA,获取完后放入了earlySingletonObjects缓存,同时将创建这个testA的工厂从缓存中删除,注意,这时候这个testA是个半成品,sharedInstance返回不为空的话就不会再走下面的getSingleton去创建了(getSingleton中有一步beforeSingletonCreation就是校验传进来的bean是否正在被创建,很显然testA正在被创建,这样就会抛出循环依赖的异常),这样就解决了循环依赖!! 好了,循环依赖基本上就讲完了,总结下,spring容器在构造器注入的时候是无法解决循环依赖的,而在setter注入的时候可以解决,但前提scope是singleton的,因为prototype的都没有三级缓存,肯定解决不了的。还是那句话,一定要自己去debug试下,这样你才能真正的理解整个过程。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值