大家都知道Spring 通过三级缓存来解决循环依赖问题,但是我今天写出来个循环依赖,直接报错,难受啊,三级缓存并没有被关闭,本篇文章我们就来深入分析一下三级缓存,以及为啥我的项目启动不了,罪魁祸首就是@Async。
1. 什么是循环依赖?
上代码!
@Service
class ServiceA {
@Autowired
ServiceB serviceB;
public void test() {
}
}
@Service
class ServiceB {
@Autowired
ServiceA serviceA;
public void test() {
}
}
复制代码
简单的说就是你中有我,我中有你,
当然也不排除你中有我,我中有她,她中有你这种复杂,甚至是更复杂的关系。
总之循环依赖就是会形成一个闭合的环形关系。
2. 循环依赖带来什么问题?
循环依赖会导致创建对象,进入死循环状态,无法创建成功。
在实例化对象A的时候,需要注入对象B,这时我们需要检查缓存中是否有对象B,如果缓存中没有对象B,这时我们需要实例化对象B,开始实例化对象B,对象B中又需要依赖A,但是这时缓存又没有构建好的A,又需要实例化A,实例化A又依赖B,B又依赖A,形成死循环,永远都不能成功创建A,B。
先实例化对象B于先实例化对象A是一样的。
3 . 如何解决循环依赖问题?
基于Java引用传递的特性,我们是可以通过缓存来解决循环依赖,我们可以将构建一半的对象放入缓存中,先进行下边的步骤,当下边的步骤创建完成后,缓存中的对象自然是完整的对象,因为缓存中我们只是存的引用地址,当对象创建好之后,半成品的对象就会变成成品对象。
3.1 一级缓存解决循环依赖
我们只通过一级缓存也是可以解决循环依赖问题的,但是会有很多问题,不够严谨,比如缓存中的对象有半成品,如果我们的对象没有打对应的标签,就可能会获取到半成品对象,引发一些诡异的问题。
- 无法很好的解决增强问题,即使用代理(必要时才提前创建代理对象)
- 无法清晰明确的区分出,哪个对象已经构建完成
3.2 二级缓存解决循环依赖问题
通过二级缓存其实我们已经可以很好的解决循环依赖问题,但是我们还是无法很好的解决增强问题,即使用代理(必要时才提前创建代理对象),通过缓存解决循环依赖问题,要求我们注入的对象必须是代理对象,才能实现增强的功能。
那么我们能不能在发生循环依赖的时候才去提前初始化代理对象呢?
那么我们