文章目录
- 前言
- 一、什么是循环依赖?
- 二、三级缓存
- 三、图解
- 三级缓存总结
前言
本文章将讲解Spring循环依赖的问题
一、什么是循环依赖?
一个或多个对象之间存在直接或间接的依赖关系,这种依赖关系构成一个环形调用,有下面 3 种方式。
模拟一个情况2的Demo
@Service
public class Service {
@Autowried
Dao dap;
}
@Repository
class Dao{
@Autowried
Service service;
}
这是一个经典的循环依赖,如果spring没有处理循环依赖,那么在他们需要注入对方属性时,会一直循环等待对方注入属性,导致无限循环。
二、三级缓存
Spring为了解决循环引用的问题,提供了三级缓存的存储方式
public class DefaultSingletonBeanRegistry ... {
//1、最终存储单例Bean成品的容器,即实例化和初始化都完成的Bean,称之为"一级缓存"
Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
//2、早期Bean单例池,缓存半成品对象,且当前对象已经被其他对象引用了,称之为"二级缓存"
Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
//3、单例Bean的工厂池,缓存半成品对象,对象未被引用,使用时在通过工厂创建Bean,称之为"三
级缓存"
Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
}
注:将对象保存至三级缓存的时候,会包装成ObjectFactory对象录入,未来通过此接口对应的get方法再
次提取对象
三、图解
图解描述:
- A实例化对象,但尚未初始化,将A存储到三级缓存中;
- A属性注入,发现需要B对象,从缓存中取,发现没有B对象;
- B实例化对象,但尚未初始化,将B放到三级缓存
- B属性注入,需要A对象,从三级缓存中通过工厂获取A对象,再将A从三级缓存移除到二级缓存,
- B执行其他生命周期的过程,最终成为一个完全体Bean,存储到一级缓存,删除二三级缓存
- A注入B对象
- A执行其他生命周期过程,最终成为一个完全体Bean,存储到一级缓存,删除二三级缓存
三级缓存总结
- 一级缓存:为“Spring 的单例属性”而生 ,就是个单例池,用来存放已经初始化完成的单例 Bean;
- 二级缓存:为“解决 AOP”而生 ,存放的是半成品的 AOP 的单例 Bean;
- 三级缓存:为“打破循环”而生 ,存放的是生成半成品单例 Bean 的工厂方法
如果没有AOP的话,其实只需要一、三级缓存,就可以解决循环引用的问题;