Spring如何解决循环依赖_三级缓存

循环依赖

循环依赖指的是就是两个或多个bean相互之间的引用,A引用B,B引用C,C又引用A,最终形成一个循环。

分类

根据循环依赖出现的情况,可以分为构造器循环依赖和属性setter循环依赖。

  1. 构造器循环依赖

    Spring无法解决这类循环依赖。原因是这种情况下,Spring 容器没办法决定先创建哪一个 bean。这时候会抛出异常 BeanCurrentlyInCreationException

  2. 单例的setter注入循环依赖

    Spring 通过三级缓存,提前暴露创建 Bean 的 ObjectFactory 解决 Setter 循环依赖。后面具体说明这个过程。

  3. 原型的setter注入循环依赖

    由于 prototype 作用域的bean,Spring容器每次都会生成一个新的对象,所以没办法通过类似单例的方法解决循环依赖问题。同样会出现Spring 容器没办法决定先创建哪一个 bean的问题。

Spring解决循环依赖的三级缓存

所谓的三级缓存,实际上指的是在Spring创建bean的三个步骤中分别缓存实例化对象。

简单地,以A依赖B,B依赖A为例,当实例化A时,我们通过调用doGetBean(“A”)来完成。在A对象实例化完成后,Spring会将该对象提前暴露出去(存放在一个Map中)。

接着,当进行属性填充时,发现A依赖了B的实例。这时候,Spring会调用doGetBean(“B”)来实例化B对象。

同样地,B对象实例化完成后,也会被提前暴露出去,存放在Map中。然后,继续填充B对象的属性,发现B依赖了A。这时,Spring不会重新实例化A对象,而是从之前提前暴露的Map中获取已经存在的A对象。

通过这种方式,B对象的属性填充完成,可以执行接下来的初始化过程。当B对象初始化完成后,再回到A对象的属性填充阶段,此时可以获取到B对象,并成功完成属性填充。

这样,Spring巧妙地解决了循环依赖的问题。通过提前暴露对象并利用Map进行缓存,避免了重复实例化的情况,确保了循环依赖的正确处理。

流程图如下:

在这里插入图片描述

Spring相关源码

public Object getSingleton(String beanName) {
   return getSingleton(beanName, true);
}

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   //首先去一级缓存中获取如果获取的到说明bean已经存在,直接返回
   Object singletonObject = this.singletonObjects.get(beanName);
   //如果一级缓存中不存在,则去判断该bean是否在创建中,如果该bean正在创建中,就说明了,这个时候发生了循环依赖
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      synchronized (this.singletonObjects) {
         //如果发生循环依赖,首先去二级缓存中获取,如果获取到则返回,这个地方就是获取aop增强以后的bean
         singletonObject = this.earlySingletonObjects.get(beanName);
         //如果二级缓存中不存在,且允许提前访问三级引用
         if (singletonObject == null && allowEarlyReference) {
            //去三级缓存中获取
            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            if (singletonFactory != null) {
               //如果三级缓存中的lambda表达式存在,执行aop,获取增强以后的对象,为了防止重复aop,将三级缓存删除,升级到二级缓存中
               singletonObject = singletonFactory.getObject();
               this.earlySingletonObjects.put(beanName, singletonObject);
               this.singletonFactories.remove(beanName);
            }
         }
      }
   }
   return singletonObject;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值