Spring如何解决循环依赖

1. 什么是循环依赖?

很简单,就是A对象依赖了B对象,B对象依赖了A对象。

例如:

// A依赖了B
class A{
    
    public B b;
}
// B依赖了A
class B{
    
    public A a;
}

那么循环依赖是个问题吗?
如果不考虑Spring,循环依赖并不是问题,因为对象之间相互依赖是很正常的事情。
 

A a = new A();
B b = new B();
a.b = b;
b.a = a;

这样,A,B就依赖上了。

2 . 三级缓存

三级缓存是通用的叫法。

  • 一级缓存为:singletonObjects
  • 二级缓存为:earlySingletonObjects
  • 三级缓存为:singletonFactories
  • singletonObjects中缓存的是已经经历了完整生命周期的bean对象。
  • earlySingletonObjects比singletonObjects多了一个early,表示缓存的是早期的bean对象。早期是什么意思?表示Bean的生命周期还没走完就把这个Bean放入了earlySingletonObjects。
  • singletonFactories中缓存的是ObjectFactory,表示对象工厂,用来创建某个对象的。

3.循环依赖问题在 Spring 中有三种情况:

  1. 通过构造方法进行依赖注入时产生的循环依赖问题
  2. 通过 setter 方法进行依赖注入时且是在多例模式下产生的循环依赖问题
  3. 通过 setter 方法进行依赖注入且是在单例模式下产生的循环依赖问题

4.分析 

在 spring 中只有第(3)种方式的循环依赖问题被解决了,其他两种方式在遇到循环依赖问题时都会产生异常,这是因为:

第一种:构造方法注入产生的循环依赖:当多个对象之间存在循环的引用关系时(也就是 A 类中注入 B 对象,同时 B 类中注入 A 对象),在初始化过程中,就会出现 “先有鸡还是先有蛋” 的问题。

@Lazy 注解:在构造方法上加上 @Lazy 注解解决构造方法造成的循环依赖问题。(本质上就是懒加载,先加载一个后加载一个)

第二种:setter 方法(多例)的情况下,每一次获取 bean 时就会产生一个新的 bean,一直下去就会产生无数的 Bean,最终会导致 OOM(内存溢出)问题的出现

 

Spring 在单例模式下的 setter 方法注入引起的循环依赖问题,主要是通过二级缓存和三级缓存来解决的,其中三级缓存是主要贡献者。

二级缓存会保存 new 出来的不完整的对象,这样当单例池中找不到依赖的属性时,就可以先从二级缓存中获取到不完整的对象并完成对象创建,然后在后续的依赖注入过程中将单例池中对象的引用关系调整完成。

三级缓存中,如果引用的对象配置了 AOP,那在单例池中最终就会需要注入动态代理对象而不是原对象。而生成动态代理是要在对象初始化完成之后才开始的。所以 Spring 增加三级缓存,保存所有对象的动态代理配置信息。在发现有循环依赖时,会将这个对象的动态代理信息获取出来,提前进行 AOP,生成动态代理。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值