Spring解决循环依赖

目录

1.循环依赖

2.出现场景

3.如何检测

4.Spring单例对象初始化步骤

5.循环依赖的解决


1.循环依赖

循环依赖就是循环引用,例如:

>依赖自身

 

>A依赖于B,B又依赖于A

 

>A依赖于B,B依赖于C,C又依赖于A

 

以上几种情况都会导致循环依赖

2.出现场景

>构造器的循环依赖

       使用构造方法的方式来注入依赖,并且类A中依赖类B,类B也同时依赖类A,这样两个类都无法正常进行Bean的创建,就会抛出异常:BeanCurrentlyInCreationException

@Component
public class A {
    private B b;
    @Autowired
    public A(B b) {
        this.b = b;
    }
}
@Component
public class B {
    private A a;
    @Autowired
    public B(A a) {
        this.a = a;
    }
}

>field属性的循环依赖

3.如何检测

在创建bean的时候可以给该bean打标签,如果递归调用回来发现正在创建的话,即说明发生了循环依赖

4.Spring单例对象初始化步骤

createBeanInstance实例化 调用对象的构造方法实例化对象

populateBean 这一步主要是对多bean的依赖属性进行填充

initializeBean 调用applicationContext.xml中的init初始化方法

5.循环依赖的解决

Spring是通过三级缓存来解决循环依赖的
一级缓存: singletonObjects存储的是所有创建好了的单例Bean
二级缓存:earlySingletonObjects完成实例化,但是还未进行属性注入及初始化的对象
三级缓存:singletonFactories提前暴露的一个单例工厂,二级缓存中存储的就是从这个工厂中获取到的对象。

通过查看DefaultSingletonBeanRegistry类的源码可以看到,三级缓存

Spring通过三级缓存解决了循环依赖,其中一级缓存为单例池(singletonObjects),二级缓存为早期曝光对象earlySingletonObjects,三级缓存为早期曝光对象工厂(singletonFactories)。 

流程如下:

1.首先 A 完成初始化第一步并将自己 提前曝光 出来(通过 ObjectFactory 将自己提前曝光),在
初始化的时候,发现自己依赖对象 B ,此时就会去尝试 get(B) ,这个时候发现 B 还没有被创建
出来;
2. 然后 B 就走创建流程,在 B 初始化的时候,同样发现自己依赖 C C 也没有被创建出来;
3. 这个时候 C 又开始初始化进程,但是在初始化的过程中发现自己依赖 A ,于是尝试 get(A) 。这
个时候由于 A 已经添加至缓存中(一般都是添加至三级缓存 singletonFactories ),通过
ObjectFactory 提前曝光,所以可以通过 ObjectFactory#getObject() 方法来拿到 A 对象。 C
A 对象后顺利完成初始化,然后将自己添加到一级缓存中;
4. 回到 B B 也可以拿到 C 对象,完成初始化, A 可以顺利拿到 B 完成初始化。到这里整个链路
就已经完成了初始化过程了。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值