文章目录
- 一、什么是循环依赖?
- 二、Spring内部解决的是那种情况下的循环依赖?
- 三、一级、二级、三级缓存保存的是什么?
- 四、如何使用三级缓存解决循环依赖?
- 五、为什么是三级缓存,二级缓存不行么?
- 六、二级缓存的作用是什么?
一、什么是循环依赖?
大白话:就是两个对象相互依赖 A依赖B B依赖A、形成一了个环,没有出口
因为spring当中bean是有生命周期的,大致创建过程:
首先创建A对象,执行A的生命周期
- 实例化A,得到一个对象
- 填充B,A内部依赖了B,去spring内部的一级缓存中找,没找到就去转到创建B的生命周期
2.1 实例化B,得到一个对象
2.2 填充B,发现B内部依赖了A,去spring内部的一级缓存中找没有
2.3 又转到了A对象的创建,死循环发生- 填充A对象内部的其他属性
- 初始化
- 放入一级缓存
二、Spring内部解决的是那种情况下的循环依赖?
解决的是单例bean下的循环依赖
如下代码:
@Component
public class A {
//A内部依赖了b属性
@Autowired
private B b;
}
@Component
public class B {
//B内部依赖了a属性
@Autowired
private A a;
}
三、一级、二级、三级缓存保存的是什么?
四、如何使用三级缓存解决循环依赖?
首先创建A对象,执行A的生命周期
- 实例化A,得到一个对象
- 将A放入三级缓存,提早暴露
- 填充B,A内部依赖了B,去spring内部的缓存中找,没找到就去转到创建B的生命周期
3.1 实例化B,得到一个对象,同时放入三级缓存
3.2 填充B,发现B内部依赖了A,去spring内部的缓存中找,此时三级缓存中找到了A
3.3 如果A需要Aop那从三级缓存里取出来的就是代理对象,否则从三级缓存里取出的就是原始对象(没有经过属性注入的)
3.4 从三级缓存里取出放到二级缓存中,同时删除三级缓存
3.5 B进行初始化操作
3.6 将B放入到一级缓存中去
3.7 B创建结束,回到A的生命周期- 填充A对象内部的其他属性
- 初始化
- 放入一级缓存
图示帮助理解:
注意:只有出现了循环依赖的情况下才会用到第二级和第三级缓存
五、为什么是三级缓存,二级缓存不行么?
也行,但是不符合bean的生命周期 (正常spring内部会在一个bean初始化后才会进行Aop)
- spring容器内部的bean都是单例的,有可能A这个对象需要被代理,那就需要提前Aop
- 如果没有三级缓存,只有二级缓存(value是对象,而不是 ObjectFactory),那么如果存在Aop需要被代理,就需要在存入二级缓存之前先去生成Aop代理对象,这是不合适的。
- 三级缓存的存在主要就是需要考虑代理的情况,所以三级缓存的value是ObjectFactory,可以从里面拿到代理对象或原始对象
六、二级缓存的作用是什么?
二级缓存主要是基于性能的考虑,避免频繁的从三级缓存的工厂里创建对象,再放到二级缓存,这样就不需要每次都从工厂里面去拿对象。
比如:
A依赖B,B依赖A
A依赖C,C依赖A
图示帮助理解:
完结。