一、什么是循环依赖、一级缓存
A、B两个Service相互依赖,类似于死锁,我们来看AServiceBean的生命周期
我们要填充bService时,在单例池找不到B,就会先去创建B。但是创建B的时候,触发B的Bean的生命周期,在单例池也找不到A,产生循环依赖。
那么怎么处理呢,就需要打破依赖
spring在2.2步解决了循环依赖
但是在4有问题
因为AOP的话,时将AService的普通对象赋值给AService的代理对象,最后加入单例池中的是AService的代理对象,所以和2.2把AService的普通对象给了B,有问题,怎么解决呢?
所以我们可以将原本的AOP过程提前,在第一步的时候就进行AOP
但是正常情况下是在4进行AOP,在1的时候怎么知道判断发生了AOP呢?
----判断不了,所以我们将AOP的过程放到2.2步
========================================
另一种情况,如果A也需要填充C,那么C也会在单例池找不到A的情况下,发现产生循环依赖了,立马生成一个AService的代理对象来进行注入吗?因为A是单例Bean,所以不可能。那么怎么解决呢,能不能把A的代理对象放到单例池吗?
肯定不能,因为没有经历过全部生命周期。
所以我们可以放到二级缓存
二、二级缓存
用来保存没有经过完整生命周期,但需要给其它单例Bean用的单例Bean
我们在创建C的时候,我们可以从二级缓存找到A的AOP代理对象,而B找不到,因为还没有放入到二级缓存
但是还是回到原来的问题,二级缓存也没有打破循环
三、三级缓存(单例工厂)
是为了打破循环
三级缓存是开始实例的时候,先添加一个lambda表达式,在2.2发现有循环依赖后,执行lambda表达式,其最终执行的是
判断是否要进行切面,如果要进行切面,则进行aop,否则返回普通对象
四、什么样的循环依赖spring解决不了
有参构造,因为普通对象根本创建不出来
public class A { private B b; public A(B b) { this.b = b; } } public class B { private A a; public B(A a) { this.a = a; } }
五、为什么加@Lazy可以解决
根本进不去循环,就像ModelAndView对象一样,Spring容器直接创造了一个B代理对象返回给A
六、三个缓存分别用的什么数据结构,为什么
一级缓存使用ConcurrentHashMap,可以支持高并发读写;二级缓存使用ConcurrentHashMap,可以避免循环依赖时的死循环问题;三级缓存使用ConcurrentHashMap和HashSet,可以支持快速的查找和删除操作。
标签:缓存,依赖,Spring,二级缓存,循环,单例,AOP,三级 From: https://www.cnblogs.com/wintermist/p/17233504.html