Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >spring源码分析之如何解决循环依赖

spring源码分析之如何解决循环依赖

作者头像
全栈程序员站长
发布于 2022-07-04 06:54:23
发布于 2022-07-04 06:54:23
43200
代码可运行
举报
运行总次数:0
代码可运行

spring-ioc中循环依赖的问题,也算是高频的面试问题了,今天跟大家一起来总结一下spring-ioc中是如何解决循环依赖的,相信大家是可以从这篇文章中彻底理解spring容器如何帮我们解决循环依赖,为了更好的理解spring-ioc如何解决循环依赖,大家可以先简单的了解spring-ioc中bean实例化的整个时序图。

一、spring-ioc解决循环依赖的位置

红色的标注框的地方,表示解决循环依赖的重点逻辑,后面会跟大家一起详细阅读,这里大家可以先有个印象

二、spring-ioc解决循环依赖的动态示意图

首先spring-ioc是无法解决构造函数中循环依赖的问题,这个后面会一起解释。咱们先用一个简单的例子和示意图来描述spring-ioc解决循环依赖的思想,最后再去阅读源码,我相信大家能更容易理解

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Service
public class ACircleService {
   

    @Autowired
    private BCircleService bCircleService;
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Service
public class BCircleService {
   

    @Autowired
    private ACircleService aCircleService;
}

相信大家经常这么使用,此时ACircleService(后面简称A)引用BCircleService(后面简称B)B中引用A就构成了一个循环依赖,下面我们用示意图来描述它们的创建过程

1、首先大家理解下面几个容器

(1)singletonsCurrentlyInCreation:表示当前正在创建的bean(仅仅存放名字beanName),如果没创建完成,都会保存在这里面

(2)singletonObjects:一级缓存,可以理解为bean最终都是放在这里面的,一个bean真正完成了就放到这里面

(3)earlySingletonObjects:二级缓存,过渡使用

(4)singletonFactories:三级缓存,也是过渡使用(提前曝光的bean存放),它与二级缓存不同的是它放的是ObjectFactory,而不是最终的Bean,二级缓存中是放的三级缓存getObject的结果

介绍完上面的容器,我们接着看在创建A,B时它是如何从上述的容器中变化

2、变化过程图

假如先创建A,此时四个容器中都是空的

(1)先依次从一级、二级、三级缓存中判断是否有能拿到A,结果显然是拿不到,四个容器都是空的,我就不画了

(2)要开始创建A,此时需要往singletonsCurrentlyInCreation放入A,表示A正在实例化,此时四个容器的状态如下

(3)接下来正式开始创建A到A创建完成(堆上面已经分配了空间,但是属性还没赋值),此时将A封装成ObjectFactory对象(为什么要封装,后面会讲一下),大家可以认为此时的A对象已经创建,但是属性未赋值,我们暂时用下面命名AObjectFactory,但是AobjectFactory.getObject() == A(A的地址假设A@9527xxx),此时A是在堆上已经创建好了,但是它的属性是null(bCircleService==null),我不知道这里有没有描述清楚,容器状态如下:

(4)此时要给A的属性赋值,这里就是给bCircleService赋值,那么就去创建B,创建B的过程和创建A的过程一样的,先依次从一级缓存、二级缓存、三级缓存中获取B,显然获取不到,那么正式开始创建B,singletonsCurrentlyInCreation中加入B,表示当前也正在创建B,容器状态如下:

(5)接下来同(3)类似,B创建完成,此时也只是在堆上创建好了对象,但是B中的属性aCircleService还没有赋值(aCircleService==null),此时将B封装成BObjectFactory放到三级缓存,容器状态如下:

(6)接下来是重点了,此时开始给B的属性赋值了,这里即给aCircleService 赋值,那么它就要去创建A,并且把A的内存地址付给B中的aCircleService属性,那么创建A的过程和之前的一样,先依次从一级、二级、三级缓存中拿A,此时是可以从三级缓存中拿到A的,那么将拿到的A赋值给B的aCircleService属性,此时aCircleService==A@9527xxx,此时B即将创建完成了,在全部创建完的前一步,将三级缓存中的B移到二级缓存(存放的是BObjectFactory.getObject()),因为实例化B的全部步骤全部做完了,此时容器的状态如下:

(7)此时B(假设地址是B@9527)已经全部实例化完成了,但是还有一些收尾的工作呀,就是需要从当前正在创建的容器(singletonsCurrentInCreation)中移除(表示B创建完成),并且同时将B移动到一级缓存singletonObjects中,此时的容器状态

(8)上述B已经创建完成了,我们要记得创建B的时机是在A给bCircleService赋值的时候,所以我们的逻辑又到了给A的属性赋值的时候了,此时我们知道B已经创建完成了,所以bCircleService==B@9527,此时A的实例化也快要结束了,A也要将三级缓存的内容移到二级缓存,类似过程(6),容器状态如下:

(9)最后A也要做一些结束的动作,类似过程(7),到这里A和B都已经全部实例化完成了

总结:上述看上去流程挺多的,其实主要的核心就是在A创建完成(对象已经在堆中分配),还没有给属性赋值(bCircleService==null)的过程中,将A封装成ObjectFactory,放到三级缓存。然后在实例化B的过程中,给B的属性aCircleService赋值时,依次 从容器中拿A,此时是可以从三级缓存中拿到,所以不会再去走创建A的过程了,相当于提前曝光了A

上面还留了两个问题,会在下面的源码分析中解释

(1)为什么spring-ioc中无法解决构造函数中的循环依赖

(2)为什么需要使用三级缓存,而且里面装的是ObjectFactory

三、源码分析

1、AbstractBeanFactory#doGetBean()

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
      @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
   

   final String beanName = transformedBeanName(name);
   Object bean;

   // Eagerly check singleton cache for manually registered singletons.
   //(1).先依次从一级、二级、三级缓存中看看能否取到
   Object sharedInstance = getSingleton(beanName);
    //(2).如果缓存中能取到,则不会走下面的创建
   if (sharedInstance != null && args == null) {
   
      if (logger.isTraceEnabled()) {
   
         if (isSingletonCurrentlyInCreation(beanName)) {
   
            logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                  "' that is not fully initialized yet - a consequence of a circular reference");
         }
         else {
   
            logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
         }
      }
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }
//(3).如果缓存中取不到,则走创建的逻辑
   else {
   
      // Fail if we're already creating this bean instance:
      // We're assumably within a circular reference.
		//省略代码...
         // Create bean instance.
         if (mbd.isSingleton()) {
   
             //(4).主要的创建逻辑
            sharedInstance = getSingleton(beanName, () -> {
   
               try {
   
                   //(5).java8函数式编程
                  return createBean(beanName, mbd, args);
               }
               catch (BeansException ex) {
   
                  // Explicitly remove instance from singleton cache: It might have been put there
                  // eagerly by the creation process, to allow for circular reference resolution.
                  // Also remove any beans that received a temporary reference to the bean.
                  destroySingleton(beanName);
                  throw ex;
               }
            });
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
         }
		//省略代码...
   }

   //省略代码...
   return (T) bean;
}

上述代码我省略了很多,主要保留了需要分析循环依赖的逻辑,上面已经加了注释

首先从一级、二级、三级缓存中取

下面的if else针对是否能从缓存中取出结果

结合上述的图,我们发现第一次创建A,显然是走else的创建逻辑getSingleton

2、DefaultSingletonBeanRegistry#getSingleton(String beanName, ObjectFactory<?> singletonFactory)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 + "'");
         }
         //(1).开始创建之前调用方法
         beforeSingletonCreation(beanName);
         boolean newSingleton = false;
         boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
         if (recordSuppressedExceptions) {
   
            this.suppressedExceptions = new LinkedHashSet<>();
         }
         try {
   
             //(2).真正的调用方法
            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;
            }
            //(3).开始创建之后调用方法
            afterSingletonCreation(beanName);
         }
         if (newSingleton) {
   
             //(4).创建成功之后调用的方法
            addSingleton(beanName, singletonObject);
         }
      }
      return singletonObject;
   }
}

我在四个核心的方法上加了注释

beforeSingletonCreation(beanName);

singletonFactory.getObject();

afterSingletonCreation(beanName);

addSingleton(beanName, singletonObject);

3、DefaultSingletonBeanRegistry#beforeSingletonCreation(beanName)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protected void beforeSingletonCreation(String beanName) {
   
   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
   
      throw new BeanCurrentlyInCreationException(beanName);
   }
}

比较简单,其实就是判断当前正在创建的容器singletonsCurrentlyInCreation是否已经包含正在创建的类,如果包含,则抛异常,我们在构造做循环依赖就会在这里抛异常,后面会具体分析为什么会在这里抛异常

4、DefaultSingletonBeanRegistry#afterSingletonCreation(beanName);

这里我们先没有分析singletonFactory.getObject()创建的核心逻辑,因为比较长一时半会儿分析不了,我们分析afterSingletonCreation是因为它和上面的beforeSingletonCreation有关联。这里我们先假设singletonFactory.getObject()已经成功执行完了,我们看afterSingletonCreation()

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protected void afterSingletonCreation(String beanName) {
   
   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
   
      throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
   }
}

很简单,就是将singletonsCurrentlyInCreation清除当前正在创建的bean,因为此时我们已经创建完了,接下来再接着看addSingleton

5、DefaultSingletonBeanRegistry#addSingleton

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protected void addSingleton(String beanName, Object singletonObject) {
   
   synchronized (this.singletonObjects) {
   
      this.singletonObjects.put(beanName, singletonObject);
      this.singletonFactories.remove(beanName);
      this.earlySingletonObjects.remove(beanName);
      this.registeredSingletons.add(beanName);
   }
}

很简单,4、5的步骤对应我们的上述第二节示意图(6)-(7)的过程。上面我们还没有分析singletonFactory.getObject()创建bean的核心逻辑,只是假设它成功调用完成了,我们现在回过头来分析

6、ObjectFactory#getObject()

这里其实是调用的AbstractAutowireCapableBeanFactory#createBean(),因为这里是使用java8的lambda表达式,传的是一个函数(参考1中代码注释(5)的那一段代码)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
   
//省略代码....
      Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    //省略代码...

}

省略了代码,我们重点看doCreateBean,这个是核心

7、AbstractAutowireCapableBeanFactory#doCreateBean

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      throws BeanCreationException {
   

   // Instantiate the bean.
   BeanWrapper instanceWrapper = null;
   if (mbd.isSingleton()) {
   
      instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
   }
   if (instanceWrapper == null) {
   
       //(1).创建bean包装类BealWrapper,这段代码执行结束,说明bean已经构建完成,在堆上创建了实例
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
    //(2).拿到bean
   final Object bean = instanceWrapper.getWrappedInstance();

   //省略部分代码...

   // Eagerly cache singletons to be able to resolve circular references
   // even when triggered by lifecycle interfaces like BeanFactoryAware.
    //(3).这里非常重要,没有删除原来的英文注释,这里就是提前曝光
   boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
         isSingletonCurrentlyInCreation(beanName));
   if (earlySingletonExposure) {
   
      if (logger.isTraceEnabled()) {
   
         logger.trace("Eagerly caching bean '" + beanName +
               "' to allow for resolving potential circular references");
      }
       //(3-1)
      addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
   }

   // Initialize the bean instance.
   Object exposedObject = bean;
   try {
   
       //(4).给属性赋值
      populateBean(beanName, mbd, instanceWrapper);
       //(5).调用初始化方法
      exposedObject = initializeBean(beanName, exposedObject, mbd);
   }
   if (earlySingletonExposure) {
   
       //(6).bean在容器中移动
      Object earlySingletonReference = getSingleton(beanName, false);

  //省略部分代码...

   return exposedObject;
}

这里是解决循环依赖的核心—即提前曝光一个实例(该实例已经创建好,但是里面的属性还没赋值,因为赋值的逻辑要到代码(4),而提前曝光的逻辑在(3))。拿上面的循环依赖A,B来说,代码执行完(3)时,A对象已经在堆上分配,只是bCircleService == null而已。此时将A提前曝光,插入到三级缓存中;而实例化B的入口则在(4)中,给bCircleservice赋值,此时如果B没有创建,就开始创建B。等B同样执行完上述(3),则B也在堆上分配了,只是暂时B中的aCircleService==null,所以B执行(4)时,去创建A,此时创建A先依次从一级、二级、三级缓存中取A时是可以在三级缓存中取到,因此代码不会执行1中的else逻辑,而是执行if。

我们现在来处理上述的第一个问题:为什么构造函数中的循环依赖不能解决?

我们还是拿A,B来举例(假如A的构造函数中依赖B),如果在构造函数中循环依赖,则A不会上述代码7中的(3)而是在(1)中就去获取B(此时注意A没有提前曝光,即一级、二级、三级缓存中都不存在),假如此时B没有创建,则开始创建B。等B执行到(4)时,给B中的aCircleService赋值时,需要去创建A,先从一级、二级、三级缓存中去取A,取不到,则走代码1中的else逻辑,else的逻辑最终会调用beforeSingletonCreation(beanName),因此就抛异常了。

我们处理第二个问题,为什么需要使用三级缓存singletonFactories,里面装的是ObjectFactory,而不是直接将ObjectFactory.getObject()获取的结果放到二级缓存earlySingletonObjects呢?

这里我们就需要看上述代码7中的(3-1)addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));这里是使用java8的函数式编程,如果不明白的,我用下面的匿名内部类来替换把

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
addSingletonFactory(beanName, new ObjectFactory<Object>(){
   

    @Override
    public Object getObject() throws BeansException {
   
        return getEarlyBeanReference();
    }
});

我们再看看getEarlyBeanReference()方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
   
   Object exposedObject = bean;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
   
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
   
         if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
   
            SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
            exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
         }
      }
   }
   return exposedObject;
}

这里无非就是对这个bean进行拦截,做一些处理,最终这个方法的调用时机,是在代码2中的(4),此时bean的实例化的基本全部完成,所以这里起到了延迟调用的作用。如果不延迟调用存在两种情况

(1)不调用getEarlyBeanReference(),则有些实例创建没有起到必要的拦截

(2)不延迟,那么可能该实例仅仅是在堆上分配了,里面属性什么都没赋值,初始化方法也没调用,可能我们用beanpostprocessor拦截也没任何意义,达不到效果。

这里大家可以思考一下这两个问题, 1.当A构造函数中依赖B,而在B中依赖A不是构造函数依赖,会不会报错 2.当A依赖B时不是构造函数依赖,而B依赖A时是构造函数依赖,会不会报错 如果大家对这两个问题都能回答正确,我相信是彻底理解了spring是如何解决循环依赖,如果回答错误,那么还需要继续看看

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/111202.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021年8月4,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Spring源码解析(五):循环依赖
在完成Bean的实例化后,属性注入之前Spring将Bean包装成一个工厂对象添加进了三级缓存中,对应源码如下:
冬天vs不冷
2025/01/21
2050
Spring源码解析(五):循环依赖
这么回答【循环依赖】助力轻松拿下阿里P6
  上图是循环依赖的三种情况,虽然方式有点不一样,但是循环依赖的本质是一样的,就你的完整创建要依赖与我,我的完整创建也依赖于你。相互依赖从而没法完整创建造成失败。
用户4919348
2022/10/04
2170
这么回答【循环依赖】助力轻松拿下阿里P6
Spring是如何解决循环依赖的
在面试的时候这两年有一个非常高频的关于spring的问题,那就是spring是如何解决循环依赖的。这个问题听着就是轻描淡写的一句话,其实考察的内容还是非常多的,主要还是考察的应聘者有没有研究过spring的源码。但是说实话,spring的源码其实非常复杂的,研究起来并不是个简单的事情,所以我们此篇文章只是为了解释清楚Spring是如何解决循环依赖的这个问题。
纪莫
2020/08/26
7180
3.4 spring5源码系列--循环依赖的设计思想
第一篇: 3.1 spring5源码系列--循环依赖 之 手写代码模拟spring循环依赖
用户7798898
2020/11/24
3680
【Spring源码】循环依赖如何处理?
面试官:“三级缓存是怎么处理的?为什么一定得是三级缓存?三级缓存别是对应存储的是什么?”
有一只柴犬
2024/01/25
2190
【Spring源码】循环依赖如何处理?
Spring系列三之Bean实例化流程
紧接着上文,Spring的Bean实例化发生在刷新IOC容器阶段的倒数第二步finishBeanFactoryInitialization(beanFactory),最终在该方法中调用DefaultListable.preInstantiateSingletons()方法实例化所有非懒加载的Bean实例,代码如下
用户9511949
2024/09/05
1560
Spring源码解析(四):单例bean的创建流程
冬天vs不冷
2025/01/21
1170
Spring源码解析(四):单例bean的创建流程
Spring源码解析(五)Spring 加载bean 依赖注入
至此,我们分析过后,可以简单的归纳一下Spring IOC容器的过程 一、Resource定位过程 这个Resource定位指的的是BeanDefinition的资源定位,他由ResourceLoader通过统一的Resource接口来完成,这个Resource对各种形式的BeanDefinition的使用都提供了统一接口,对于这些BeanDefinition的存在形式,相信大家都不会感到陌生,比如,在类路径中的Bean定义信息可以使用FileSystemResouce来进行抽象;在类路径中的Bean定义信息可以使用前面提到的ClassPathResource来使用,等待;这个定位过程类似于容器寻找数据的过程,就像用水桶装水先要把水找到一样;
石臻臻的杂货铺[同名公众号]
2021/07/14
5870
Spring AOP源码分析——基本概念介绍
Aspect Oriented Programming (AOP) 是一种编程范式,它旨在提供一种方法来增强应用程序的功能和模块化横切关注点。
用户1413827
2023/11/28
1730
烂了大街的 Spring 循环依赖问题,你觉得自己会了吗
初学 Spring 的时候,我们就知道 IOC,控制反转么,它将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理,不需要我们手动去各种 new XXX。
海星
2020/09/09
6860
Spring篇之循环依赖
循环依赖就是多个Bean之间存在相互依赖,形成一个闭环,如下,PostService和UserService之间就存在相互依赖,这个依赖并不是方法 之间的依赖,而是Bean与Bean之间的依赖。
小四的技术之旅
2022/07/26
1.6K0
Spring篇之循环依赖
逐行阅读Spring5.X源码(十)spring如何解决循环引用,bean实例化过程源码详解
bean的实例化是在refresh()——>finishBeanFactoryInitialization(beanFactory);方法里完成的。当然,只能实例化单例的类。
源码之路
2020/09/04
8000
逐行阅读Spring5.X源码(十)spring如何解决循环引用,bean实例化过程源码详解
Spring 是如何解决循环依赖的?
正要创建的 bean 记录在缓存中,Spring 容器架构一个正在创建的 bean 标识符放在一个 “当前创建 bean 池”中国, 因此如果在创建 Bean 过程中,如果发现已经在当前创建的 Bean 池中,则抛出 BeanCurrentlyInCreationException 异常表示循环依赖,对于创建完毕的 Bean 将从“当前创建 Bean 池”中清除。 先看个例子:
王小明_HIT
2020/08/14
9000
【彻底搞懂】Spring之三级缓存解决循环依赖问题
spring解决循环依赖是通过对象的实例化和初始化分开的步骤来实现的,如果是构造函数注入的话,对象实例化就卡住了
西柚dzh
2022/06/09
3.8K2
【彻底搞懂】Spring之三级缓存解决循环依赖问题
spring如何解决循环依赖
使用构造器注入构成循环依赖,这种方式无法进行解决,抛出了BeanCurrentlyInCreationException异常
科技新语
2024/08/16
970
spring如何解决循环依赖
Spring系列第56篇:一文搞懂spring到底为什么要用三级缓存??
本文未指明 bean scope 默认情况下,所有 bean 都是单例的,即 scope 是 singleton,即下面所有问题都是在单例的情况下分析的。
路人甲Java
2021/03/03
5.6K0
Spring系列第56篇:一文搞懂spring到底为什么要用三级缓存??
spring解决循环依赖
spring 单例对象的实例化、初始化过程是在doCreateBean中(之前仅仅是注册好了BeanDefenition), 大概分为三步:
leobhao
2022/06/28
5170
一篇文章带你读懂Spring如何解决循环依赖!
当多个Bean相互依赖时则构成了循环依赖,例如A,B两个Bean。其中A中存在属性B,B中存在属性A,当Spring在实例化A时发现A中存在属性B,就去实例化B,实例化B时又发现存在属性A,一直在循环注入依赖,导致循环依赖问题出现。
Java程序猿
2021/06/25
4100
Spring循环依赖三级缓存是否可以减少为二级缓存?
我们都知道Spring通过三级缓存来解决循环依赖的问题,那么是不是必须是三级缓存?二级缓存不能解决吗?
程序员白楠楠
2021/01/29
9160
透过源码,捋清楚循环依赖到底是如何解决的!
关于 Spring 循环依赖,松哥已经连着发了三篇文章了,本篇文章松哥从源码的角度来和小伙伴们捋一捋 Spring 循环依赖到底是如何解决了。如果没看过前面的文章建议先看一下,大家在面试中如果遇到循环依赖相关的问题,其实看前面三篇文章就可以答出来了,本文主要是从源码角度来验证一下我们前面文章所讲的内容是无误的。
江南一点雨
2023/09/09
2490
透过源码,捋清楚循环依赖到底是如何解决的!
推荐阅读
相关推荐
Spring源码解析(五):循环依赖
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验