Spring三级缓存
时间:2021-04-22 16:18:40
收藏:0
阅读:0
Spring解决循环依赖的问题
// 业务开发中经常这么写,field注入、setter注入都OK,但是构造器注入会报错BeanCurrentlyInCreationException
// 有这种循环依赖问题存在Spring却依然能够正常启动工作,为什么?Spring帮我们搞定了:三级缓存
@Service
public class AServiceImpl implements AService {
@Autowired
private BService bService;
}
@Service
public class BServiceImpl implements BService {
@Autowired
private AService aService;
}
在创建过程中,都是从三级缓存(对象工厂创建不完整对象),将提前暴露的对象放入到二级缓存,从二级缓存拿到后,完成初始化,放入一级缓存。
名称 描述 singletonObjects 一级缓存,存放完整的 Bean。 earlySingletonObjects 二级缓存,存放提前暴露的Bean,Bean 是不完整的,未完成属性注入和执行 init 方法。 singletonFactories 三级缓存,存放的是 Bean 工厂,主要是生产 Bean,存放到二级缓存中。
A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象”这种循环依赖的情景。
- 实例化 A,此时 A 还未完成属性填充和初始化方法(@PostConstruct)的执行,A 只是一个半成品。
- 为 A 创建一个 Bean 工厂,并放入到 singletonFactories 中。
- 发现 A 需要注入 B 对象,但是一级、二级、三级缓存均为发现对象 B。
- 实例化 B,此时 B 还未完成属性填充和初始化方法(@PostConstruct)的执行,B 只是一个半成品。
- 为 B 创建一个 Bean 工厂,并放入到 singletonFactories 中。
- 发现 B 需要注入 A 对象,此时在一级、二级未发现对象 A,但是在三级缓存中发现了对象 A,从三级缓存中得到对象 A,并将对象 A 放入二级缓存中,同时删除三级缓存中的对象 A。(注意,此时的 A 还是一个半成品,并没有完成属性填充和执行初始化方法)
- 将对象 A 注入到对象 B 中。
- 对象 B 完成属性填充,执行初始化方法,并放入到一级缓存中,同时删除二级缓存中的对象 B。(此时对象 B 已经是一个成品)
- 对象 A 得到对象 B,将对象 B 注入到对象 A 中。(对象 A 得到的是一个完整的对象 B)
- 对象 A 完成属性填充,执行初始化方法,并放入到一级缓存中,同时删除二级缓存中的对象 A。
一定需要三级缓存吗?
? 和AOP有关,第三级缓存的目的是为了延迟代理对象的创建(以应对循环依赖问题)。如果可以在实例化完成后立即创建代理对象,就不需要三级缓存了,所以二级缓存也是可以解决循环依赖的。为啥要额外多添加一层缓存?因为 Spring 的设计原则是在 Bean 初始化完成之后才为其创建代理
评论(0)