Spring循环依赖与三级缓存原理分析

1.什么是循环依赖?

这个不过多赘述,简单来说,就是A依赖B,B依赖A,创建Bean的时候就出现了死循环(创建A的时候需要B,创建B的时候需要A)。

2.spring是如何解决的?

依靠三级缓存解决。

第一级缓存:也就是单例池,存放着经过完整生命周期的bean。

第二级缓存:存放早期bean(未经过完整生命周期),可能是原始对象,也可能是代理对象

第三级缓存:存放生成bean的工厂,通过工厂可以获取代理对象。

创建流程:创建ABean——放入三级缓存——填充属性(需要BBean)——创建BBean——填充属性(需要ABean)——从三级缓存中获取(一、二级缓存没有)——执行获取ABean的方法获取ABean(如果A需要AOP,这里会提前进行AOP生成A的代理对象)——ABean放入二级缓存——从二级缓存中获取ABean完成BBean的属性填充——完成BBean的初始化——完成ABean的属性填充——完成ABean的初始化——添加到单例池。

3.为什么需要三级缓存,一、二级缓存行不行?

一级缓存肯定不行,因为一级缓存存放的都是经过完整生命周期的bean,可以直接用的,未初始化完成的bean放进去,如果直接被使用可能会出现问题。

二级缓存其实可以,如果存在AOP,不管有没有循环依赖,提前进行AOP就可以。例如,A实例化之后,直接进行AOP生成代理对象,放入二级缓存,此时创建B,可以直接从二级缓存中取出A的代理对象。但是,为了不完全违背bean的生命周期定义(AOP应该在填充属性之后进行),选择引入三级缓存,只在存在循环依赖时,才提前进行AOP。这样,不会完全违背bean的生命周期定义。

4.可不可以在实例化的时候判断有没有循环依赖,这样也不需要三级缓存,也不完全违背bean的生命周期定义?

实例化的时候没有太好的方法进行判断。依赖注入的时候判断比较容易,可以引入一个set,存放正在创建的bean。例如,创建A的时候,A放入set,填充属性(依赖注入)的时候,需要创建B,B也放入set,B进行依赖注入的时候,创建A的时候发现set中存在A,代表A也在创建中,就知道出现了循环依赖,此时就需要提前进行AOP。

5.@Lazy为什么能解决循环依赖?

@Lazy标记的属性或者构造方法,进行依赖注入时会生成该属性的代理对象进行赋值,不依赖原始对象的创建,此时也就没有循环依赖,就能正常创建。

6.spring在哪些情况下解决不了循环依赖?(@Lazy可以解决)

(1)多例Bean的循环依赖

(2)构造器注入的Bean的情况,无法实例化

(3)有@Async注解增强类的循环依赖,因为@Async不是通过AOP实现,不会提前生成代理对象,导致其他对象持有的引用是原始对象,而不是增强后的代理对象。

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值