更多文章点击--spring源码分析系列

1、spring循环依赖场景
2、循环依赖解决方式: 三级缓存

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

pojo.java

ioc-CirculationReference.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
  5.    <!--使用构造函数互相引用 -->
  6. <bean id="circulationb" class="com.nancy.ioc.CirculationReference.CirculationB" >
  7. <constructor-arg name="circulationA" ref="circulationa"/>
  8. </bean>
  9. <bean id="circulationa" class="com.nancy.ioc.CirculationReference.CirculationA" >
  10. <constructor-arg name="circulationB" ref="circulationb"/>
  11. </bean>
  12. </beans>

CirculationReferenceTest代码

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

CirculationReferenceTest.java

错误堆栈信息: 验证了spring无法解决第一种循环依赖

  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如下并再次运行:  验证第二种情况, 此时运行结果正常.

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
  5. <!-- B的filed依赖A A构造函数依赖B -->
  6. <bean id="circulationb" class="com.nancy.ioc.CirculationReference.CirculationB" >
  7. <property name="circulationA" ref="circulationa"/>
  8. </bean>
  9. <bean id="circulationa" class="com.nancy.ioc.CirculationReference.CirculationA" >
  10. <constructor-arg name="circulationB" ref="circulationb"/>
  11. </bean>
  12. </beans>

 如果将 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. @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. protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
  62. throws BeanCreationException;

AbstractBeanFactory.java

在DefaultSingletonBeanRegistry使用三级缓存:

  1. // 第一层: 初始化完备的单例bean
  2. /** Cache of singleton objects: bean name to bean instance. */
  3. private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
  4. // 第二层: 提前暴光的单例对象的Cache
  5. /** Cache of early singleton objects: bean name to bean instance. */
  6. private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
  7. // 第三层: ObjectFactory工厂bean缓存, 存储实例话后的bean Factory
  8. /** Cache of singleton factories: bean name to ObjectFactory. */
  9. private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

从缓存中获取单例对象

  1. protected Object getSingleton(String beanName, boolean allowEarlyReference) {
  2. // 首先从第一层缓存获取
  3. Object singletonObject = this.singletonObjects.get(beanName);
  4. // 其次第一层未找到缓存 且 bean处于创建中(例如A定义的构造函数依赖了B对象,得先去创建B对象,或者在populatebean过程中依赖了B对象,得先去创建B对象,此时A处于创建中)
  5. if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
  6. synchronized (this.singletonObjects) {
  7. singletonObject = this.earlySingletonObjects.get(beanName);
  8. // 最后第二层未找到缓存 并 允许循环依赖即从工厂类获取对象
  9. if (singletonObject == null && allowEarlyReference) {
  10. ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
  11. if (singletonFactory != null) {
  12. singletonObject = singletonFactory.getObject();
  13. // 此时会将三级缓存 移入 二级缓存
  14. this.earlySingletonObjects.put(beanName, singletonObject);
  15. this.singletonFactories.remove(beanName);
  16. }
  17. }
  18. }
  19. }
  20. return (singletonObject != NULL_OBJECT ? singletonObject : null);
  21. }

getSingleton(String beanName, boolean allowEarlyReference)

创建并缓存单例对象: 创建过程中会暂时先标记bean为创建中, 创建完成之后会清楚该标记并加入第一级缓存

  1. // 创建并注册单例对象 如果存在直接返回
  2. public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
  3. Assert.notNull(beanName, "Bean name must not be null");
  4. synchronized (this.singletonObjects) {
  5. Object singletonObject = this.singletonObjects.get(beanName);
  6. if (singletonObject == null) {
  7. if (this.singletonsCurrentlyInDestruction) {
  8. throw new BeanCreationNotAllowedException(beanName,
  9. "Singleton bean creation not allowed while singletons of this factory are in destruction " +
  10. "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
  11. }
  12. if (logger.isDebugEnabled()) {
  13. logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
  14. }
  15. // 标记创建开始, 用于标记创建中 多次创建会抛出BeanCurrentlyInCreationException
  16. beforeSingletonCreation(beanName);
  17. boolean newSingleton = false;
  18. boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
  19. if (recordSuppressedExceptions) {
  20. this.suppressedExceptions = new LinkedHashSet<>();
  21. }
  22. try {
  23. // 使用工厂方法获取单例
  24. singletonObject = singletonFactory.getObject();
  25. newSingleton = true;
  26. }
  27. catch (IllegalStateException ex) {
  28. // Has the singleton object implicitly appeared in the meantime ->
  29. // if yes, proceed with it since the exception indicates that state.
  30. singletonObject = this.singletonObjects.get(beanName);
  31. if (singletonObject == null) {
  32. throw ex;
  33. }
  34. }
  35. catch (BeanCreationException ex) {
  36. if (recordSuppressedExceptions) {
  37. for (Exception suppressedException : this.suppressedExceptions) {
  38. ex.addRelatedCause(suppressedException);
  39. }
  40. }
  41. throw ex;
  42. }
  43. finally {
  44. if (recordSuppressedExceptions) {
  45. this.suppressedExceptions = null;
  46. }
  47. // 标记创建结束
  48. afterSingletonCreation(beanName);
  49. }
  50. // 保存入一级缓存 并 清空其他缓存
  51. if (newSingleton) {
  52. addSingleton(beanName, singletonObject);
  53. }
  54. }
  55. return singletonObject;
  56. }
  57. }

getSingleton(String beanName, ObjectFactory<?> singletonFactory)

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

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

标记和清除bean处于创建中方法

AbstractAutowireCapableBeanFactory中doCreateBean: 核心createBeanInstance、addSingletonFactory、populateBean

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

ConstructorResolver

  1. public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
  2. @Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {
  3.  
  4. // ........
  5.  
  6. int minNrOfArgs;
  7. if (explicitArgs != null) {
  8. minNrOfArgs = explicitArgs.length;
  9. }
  10. else {
  11. ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
  12. resolvedValues = new ConstructorArgumentValues();
  13. minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
  14. }
  15.  
  16. // ........
  17. }
  18.  
  19. private int resolveConstructorArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw,
  20. ConstructorArgumentValues cargs, ConstructorArgumentValues resolvedValues) {
  21.  
  22. //.......
  23.  
  24. for (ConstructorArgumentValues.ValueHolder valueHolder : cargs.getGenericArgumentValues()) {
  25. if (valueHolder.isConverted()) {
  26. resolvedValues.addGenericArgumentValue(valueHolder);
  27. }
  28. else {
  29. Object resolvedValue =
  30. valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
  31. ConstructorArgumentValues.ValueHolder resolvedValueHolder = new ConstructorArgumentValues.ValueHolder(
  32. resolvedValue, valueHolder.getType(), valueHolder.getName());
  33. resolvedValueHolder.setSource(valueHolder);
  34. resolvedValues.addGenericArgumentValue(resolvedValueHolder);
  35. }
  36. }
  37.  
  38. return minNrOfArgs;
  39. }

ConstructorResolver.java

BeanDefinitionValueResolver

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

BeanDefinitionValueResolver.java

首先需要明确spring对象如果拿不到构造参数将无法使用构造函数实例化,  所以如果构造函数依赖于其他对象必然先去创建其他对象. 如果是使用默认空参构造则可以实例化, 如果初始化阶段依赖于其他对象必然会去创建其他对象.

  • 第一个demo情况, 当createBeanInstance使用构造函数创建circulationA需要依赖circulationB, 则会暂时停下来并会创建circulationB 并由于对应未创建并不会加入三级缓存.  当使用构造函数创建circulationB需要依赖circulationA, 则也会暂时停下来并会创建circulationA 并由于对应未创建并不会加入三级缓存. 当创建circulationA会再次调用beforeSingletonCreation进行标记, 因为会抛出BeanCurrentlyInCreationException异常终止ioc容器初始化. circulationA和circulationB 由于各自拿不到对应的构造函数参数而无法实例化
  • 第二个demo情况, circulationB使用setter依赖circulationA, 因此createBeanInstance使用默认的空参数构造实例化, 完成之后加入三级缓存并在populateBean中属性进行初始化, 此时需要实例化circulationA.  当使用构造函数创建circulationA需要依赖circulationB, 则也会暂时停下来并去创建circulationB, 由于在缓存中拿到circulationB即完成circulationA实例化. 再次返回circulationB的populateBean方法. 此时circulationA 和 circulationB 加载完成.  由此可以类推, 如果只是通过属性 或者 setter方法进行循环依赖 spring可以完美解决.
  • 在第二个demo情况中将  circulationB 和  circulationA 声明顺序进行交换依然导致了加载错误. 根源问题在于与第一种情况一样, circulationA拿不到对应的构造函数参数而无法实例化 未进入三级缓存, 故而导致了circulationB再次创建circulationA的时候, 由beforeSingletonCreation抛出BeanCurrentlyInCreationException异常终止ioc容器初始化.

因此得出结果spring解决的循环依赖只是部分, 而无法解决的情况是在使用构造函数互相引用的场景. spring bean声明中应避免第一种情况 和 第一种情况的变种情况.

参考链接:

Spring源码初探-IOC(4)-Bean的初始化-循环依赖的解决
Spring-bean的循环依赖以及解决方式

spring如何解决单例循环依赖问题?的更多相关文章

  1. Spring里bean之间的循环依赖解决与源码解读

    通过前几节的分析,已经成功将bean实例化,但是大家一定要将bean的实例化和完成bean的创建区分开,bean的实例化仅仅是获得了bean的实例,该bean仍在继续创建之中,之后在该bean实例的基 ...

  2. Spring源码分析之循环依赖及解决方案

    Spring源码分析之循环依赖及解决方案 往期文章: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 Spring源码分析之BeanFactoryPostPro ...

  3. 展开说说,Spring Bean IOC、AOP 循环依赖

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 延迟满足能给你带来什么? 大学有四年时间,但几乎所有人都是临近毕业才发现找一份好工作 ...

  4. Spring源码-IOC部分-循环依赖-用实例证明去掉二级缓存会出现什么问题【7】

    实验环境:spring-framework-5.0.2.jdk8.gradle4.3.1 Spring源码-IOC部分-容器简介[1] Spring源码-IOC部分-容器初始化过程[2] Spring ...

  5. 再探循环依赖 → Spring 是如何判定原型循环依赖和构造方法循环依赖的?

    开心一刻 一天,侄子和我哥聊天,我坐在旁边听着 侄子:爸爸,你爱我妈妈吗? 哥:这话说的,不爱能有你吗? 侄子:确定有我不是因为荷尔蒙吗? 哥:因为什么荷尔蒙,因为爱情! 侄子:那我妈花点钱,你咋老说 ...

  6. Spring IOC原理补充(循环依赖、Bean作用域等)

    文章目录 前言 正文 循环依赖 什么是循环依赖? Spring是如何解决循环依赖的? 作用域实现原理以及如何自定义作用域 作用域实现原理 自定义Scope BeanPostProcessor的执行时机 ...

  7. Spring源码--debug分析循环依赖--构造器注入

    目的:源码调试构造器注入,看看是怎么报错的. spring:5.2.3 jdk:1.8 一.准备 首先准备两个循环依赖的类:userService和roleServic <bean id=&qu ...

  8. Spring对象类型——单例和多例

    由于看淘淘商城的项目,涉及到了项目中处理spring中bean对象的两种类型,分别是单例和多例,就在此记录一下,方便加深理解,写出更加健壮的代码. 一.单例和多例的概述 在Spring中,bean可以 ...

  9. Spring 事务、异步和循环依赖有什么关系?

    前言 在循环依赖中有一种循环依赖,就是自注入:自己依赖自己. 事务的自注入 在 Spring 自调用事务失效,你是怎么解决的? 有小伙伴提出可以自己注入自己来解决事务失效. 具体使用方式如下: @Sl ...

随机推荐

  1. Project Euler Problem8

    Largest product in a series Problem 8 Find the greatest product of five consecutive digits in the 10 ...

  2. Java快速学习笔记01

    这一波快速学习主要是应付校招笔面试用,功利性质不可避免. 学习网址: http://www.runoob.com/java/java-tutorial.html 执行命令解析: 以上我们使用了两个命令 ...

  3. ANN算法总结

    kd-tree kd-tree works poorly in high dimensions (k<30) 自己实验的时候差不多20到30左右吧,超过之后,就真的很慢了 faiss suppo ...

  4. CNN中各种各样的卷积

    https://zhuanlan.zhihu.com/p/29367273 https://zhuanlan.zhihu.com/p/28749411 以及1*1卷积核:https://www.zhi ...

  5. zabbix server+agent+proxy搭建性能监控平台

    这是新找到了配置文件配置方法但未尝试 每个模块工作职责: Zabbix Server:负责接收agent发送的报告信息的核心组件,所有配置,统计数据及操作数据均由其组织进行: Database Sto ...

  6. python 全栈开发,Day103(微信消息推送,结算中心业务流程)

    昨日内容回顾 第一部分:考试题(Python基础) 第二部分:路飞相关 1. 是否遇到bug?难解决的技术点?印象深刻的事? - orm操作费劲 - 最开始学习路由系统时候,匹配规则: 答案一: 有, ...

  7. Codeforces 707E Garlands

    Garlands 我怎么感觉好水啊. 因为询问只有2000组, 离线询问, 枚举联通块再枚举询问, 二维树状数组更新答案. #include<bits/stdc++.h> #define ...

  8. Educational Codeforces Round 26-D. Round Subset

    题目大意:给你n个数字(小于1e18),从n个数中取k个数字相乘,使其后缀0最多,问你后缀0最多是多少. 知道得用三维的dp[ i ] [ j ] [ k ]  第一维表示用到第 i 个数为止,j 表 ...

  9. Mysql数据库改名

    转自:https://www.cnblogs.com/leffss/p/7832100.html #!/bin/bash #作者:fafu_li #时间:2015.08.10 #mysql数据库改名, ...

  10. Floyd-傻子也能看懂的弗洛伊德算法(转)

                暑假,小哼准备去一些城市旅游.有些城市之间有公路,有些城市之间则没有,如下图.为了节省经费以及方便计划旅程,小哼希望在出发之前知道任意两个城市之前的最短路程.          ...