Spring如何解决循环依赖

一.什么是循环依赖?

是一个或多个对象实例之间存在直接或间接的依赖关系,这种关系构成了一个环形调用。

第一种情况:自己依赖自己

A对象自己依赖自己

第二种情况:两个对象之间的直接依赖

A对象和B对象相互依赖,形成循环

第三种情况:多个对象之间的间接依赖,形成循环

例子:两个对象之间的直接依赖

@Service
public class Service1 {
    @Autowired
    private Service2 service2;

    public void test1(){

    }
}
@Service
public class Service2 {
    @Autowired
    private Service1 service1;
    public void test2(){

    }
}

循环依赖的场景

所以不是所有的循环依赖Spring都可以解决

单例的setter注入,是目前我们用的最多的,就是上面展示的两个对象的直接依赖

这种依赖,Spring默默的帮我们解决了。

Spring内部有三级缓存:

  • singletonObjects 一级缓存,用于保存实例化、注入、初始化完成的bean实例
  • earlySingletonObjects 二级缓存,用于保存实例化完成的bean实例
  • singletonFactories 三级缓存,用于保存bean创建工厂,以便于后面扩展有机会创建代理对象。

这三级缓存对应的源码:

/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); // 一级缓存

/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 二级缓存

/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16); // 三级缓存

单例Bean初始化完成,要经历三步:

实例化 属性赋值 初始化

我们用最常用的单例setter注入来解释一下三级缓存解决循环依赖的过程

1.创建A实例,实例化的时候先把A对象工厂放入三级缓存,三级缓存就是用来保存工厂的,没有经历过一二级缓存,还不完整,先曝光,让我们它有了,

2.第二步,属性赋值,注入就发生在这,因为内部依赖了B,B还没有被创建出来,去实例化B

3.同时B也走到了第二步时,内部依赖了A对象,然后会从一到三级缓存去查A,因为A对象工厂先放到三级缓存曝光,还不完善,但有,把A放入二级缓存,同时删除三级缓存中的A,此时,B已经实例化并且初始化完成,把B放入⼀级缓存。

4.接着A继续属性赋值,顺利从⼀级缓存拿到实例化且初始化完成的B对象,A对象创建也完成,删除⼆级缓存中的A,同时把A放⼊⼀级缓存

5.最后,⼀级缓存中保存着实例化、初始化都完成的A、B对象

实例化和属性赋值是分开的,所以Spring能解决setter注入的循环依赖了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值