Spring如何解决循环依赖

1、什么是循环依赖

在这里插入图片描述
简单来说就是,A依赖B的同时,B也依赖A,就构成了循环依赖。还有自己依赖自己的直接依赖以及多个对象之间的间接依赖
Spring能够解决的是单例的setter注入时的循环依赖,有可能解决单例的代理对象setter注入

2、如何解决循环依赖

@Service
public class A{
 
    @Autowired
    private B b;
 
    public void test1() {
    }
}
 
@Service
public class B{
 
    @Autowired
    private A a;
 
    public void test2() {
    }
}

这是一个经典的循环依赖,但是它能正常运行,得益于spring的内部机制,让我们根本无法感知它有问题,因为spring默默帮我们解决了。

我们都知道,单例 Bean 初始化完成,要经历三步:
在这里插入图片描述
注入就发生在第二步,属性赋值,结合这个过程,Spring 通过三级缓存解决了循环依赖:

一级缓存 : Map<String,Object> singletonObjects,单例池,用于保存实例化、属性赋值(注入)、初始化完成的 bean 实例
二级缓存 : Map<String,Object> earlySingletonObjects,早期曝光对象,用于保存实例化完成的 bean 实例
三级缓存 : Map<String,ObjectFactory<?>> singletonFactories,早期曝光对象工厂,用于保存 bean 创建工厂,以便于后面扩展有机会创建代理对象。

下面通过A依赖B,B依赖A这个例子,来一步一步分析Spring是如何解决循环依赖的:

当我们去调用 getBean()方法的时候,Spring 会先从一级缓存中去找到目标 Bean,如果发现一级缓存中没有便会去二级缓存中去找,而如果一、二级缓存中都没有找到,意味着该目标 Bean还没有实例化。于是,Spring 容器会实例化目标 Bean

A实例的初始化过程:

  1. 因为A在此之前还未被创建,且A比B提前被扫描到,于是创建 A 实例,实例化的时候把 A 对象⼯⼚放⼊三级缓存,表示 A 开始实例化了,虽然我这个对象还不完整,但是先曝光出来让大家知道。
  2. 开始属性注入,A 注⼊属性时,发现依赖 B,则依次从一级到三级缓存查询B,此时 B 还没有被创建出来,所以去实例化 B。
  3. 同样,B 注⼊属性时发现依赖 A,它就会从缓存里找 A 对象。依次从⼀级到三级缓存查询 A,从三级缓存通过对象⼯⼚拿到 A,发现 A 虽然不太完善,但是存在,把 A 放⼊⼆级缓存,同时删除三级缓存中的 A,此时,B 已经实例化并且初始化完成,把 B 放入⼀级缓存。
  4. 接着 A 继续属性赋值,顺利从⼀级缓存拿到实例化且初始化完成的 B 对象,A 对象创建也完成,删除⼆级缓存中的 A,同时把 A 放⼊⼀级缓存
  5. 最后,⼀级缓存中保存着实例化、初始化都完成的 A、B 对象
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值