Spring三级缓存与解决循环依赖

一、什么是循环依赖、一级缓存

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,可以支持快速的查找和删除操作。

 

posted @ 2023-03-19 16:24  冬日寻雾记  阅读(937)  评论(0)    收藏  举报