什么是循环依赖?怎么去解决这个循环依赖?为什么循环依赖需要三级缓存?

什么是循环依赖?

循环依赖(Circular Dependency)是指俩个或者多个模块、类、组件之间相互依赖,形成一个闭环。简而言之呢就是A依赖B,B依赖A,这会导致依赖的循环,无法确定加载和初始化的一个顺序。

简单示例:

@Service
public class A {
    @Autowired
    private B b;
}

@Service
public class B {
    @Autowired
    private A a;
}

//或者自己依赖自己
@Service
public class A {
    @Autowired
    private A a;
}

上面这俩种方式都是循环依赖,应该很好理解,当然也可以是三个Bean甚至是更多的Bean相互依赖,原理都是一样的。

Spring如何解决循环依赖?

Spring解决循环依赖的关键就在于提前暴露未完全创建完毕的Bean

在Spring中主要使用的是三级缓存来解决循环依赖:

一级缓存(Singleton Objects Map): 用于存储完全初始化完成的Bean

二级缓存(Early Singleton Objects Map):用于存储尚未完全初始化,但是已经实例化的Bean,用于提前暴露,避免循环依赖。

三级缓存(Singleton Factories Map):用于存储对象工厂,当需要时,可以通过工厂创建早期的Bean(特别是为了支持AOP代理对象的创建)

解决步骤:

1)Spring首先会创建Bean实例,并将其加入到三级缓存中(Factory)

2)当一个Bean依赖另一个未初始化的Bean时,Spring会从三级缓存中获取到Bean的工厂,并生成该Bean的对象(若有代理则是代理对象)

3)代理对象存入二级缓存,解决循环依赖

4)一旦所有依赖Bean被完全初始化,Bean将转移到一级缓存中。

扩展知识:

在Spring中,只有同时满足以下俩点才能解决循环依赖的问题:

1.依赖的Bean必须是单例

2.依赖注入的方式,必须不全是构造器注入,且beanName字母序在前的不能时构造器注入

这三个map是如何配合的呢?

1.首先,获取单例Bean的时候会通过BeanName先去一级缓存查找完整的Bean,如果找到直接返回,否者进行步骤2

2.看对应的Bean是否在创建中,如果不在直接返回找不到,如果是,则会去二级缓存查找Bean,如果找到则返回,否则进行步骤3

3.去三级缓存通过BeanName查找对应的工厂,如果存在工厂则通过工厂创建Bean,并且放置到二级缓存中。

4.如果三个缓存都没有找到,则返回null

为什么Spring循环依赖需要三级缓存,二级不够吗?

Spring之所以需要三级缓存而不是简单的二级缓存,主要的原因是AOP代理和Bean的早期引用问题

二级缓存虽然可以解决循环依赖的问题,但是涉及到动态代理(AOP)时,直接使用二级缓存不做任何处理会导致我们拿到的Bean是未代理的原始对象。如果二级缓存内存放的都是代理对象,就违反了Bean的生命周期。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值