Spring-bean的循环依赖以及解决方式

一. 什么是循环依赖?

多个bean之间相互依赖,形成了一个闭环,比如:A依赖于B、B依赖于C、C依赖于A

在这里插入图片描述

二:两种注入方式对循环依赖的影响

在通过IOC创建对象的时候,如果这个对象还有属性,会一并赋值进去,这个属性赋值有两种方式,构造器属性注入,set方法注入,

  1. 构造器属性注入: 构造器属性注入没有办法解决循环依赖
  2. set方法注入: 注入方式是set且单例,就不会有循环依赖问题
    原型(Prototype)的场景是不支持循环依赖的,报错(BeanCurrentlylnCreationException)

三:spring是怎么判断一个类是否创建代理对象的

Spring会根据类的特性(是否实现接口、是否被切面所影响等)和配置(是否使用@Transactional注解等)来判断是否需要为某个类创建代理对象。

四:spring内部通过3级缓存来解决循环依赖

第一级缓存:〈也叫单例池)singletonObjects:存放已经经历了完整生命周期的Bean对象
第二级缓存: earlySingletonObjects,存放早期暴露出来的Bean对象,用于保存实例化完成的bean实例,用来解决普通对象创建过程中的循环依赖问题
第三级缓存: Map<String, ObiectFactory<?>> singletonFactories,存放可以生成Bean的工厂,用来解决存在 AOP 时的循环依赖问题

在这里插入图片描述
在这里插入图片描述

四:循环依赖具体流程

  1. 调用 doGetBean()方法,想要获取 beanA ,于是调用 getSingleton方法从缓存中查找beanA
  2. 在 getSingleton() 方法中,从一级缓存中查找,没有,返回 null
  3. doGetBean()方法中获取到 beanA 为 null ,于是走对应的处理逻辑,调用 getSingleton()的重载方法(参数为 Objectfactory 的)
  4. 在 getSingleton()方法中,先将 beanA_name 添加到一个集合中,用于标记该 bean 正在创建中,然后回调匿名内部类的 createBean 方法
  5. 进入 AbstractAutowireCapableBeanFactory#doCreateBean,先反射调用构造器创建出 beanA 的实例,然后判断,是否为单例,是否允许提前暴露引用(对于单例一般为true)、是否正在创建中(即是否是在第四步的集合中)判断为 true 则将 beanA 添加到【三级缓存】中
  6. 对 beanA 进行属性填充,此时检测到 beanA 依赖于 beanC ,于是查找 beanC
  7. 调用 doGetBean() 方法,和上面 beanA 的过程一样,到缓存中查询 beanC ,没有则创建,然后给 beanC 填充属性
  8. 此时 beanC 依赖于 beanA,调用 getSingleton()获取 beanA.依次从一级、二级、三级缓存中找、此时从三级缓存中获取到 beanA 的创建工厂,通过创建工厂获取到 singletonObject ,此时这个 singletonObject 指向的就是上面在 doCreateBean()方法中实例化的 beanA
  9. 这样 beanC 就获取到了 beanA 的依赖,于是 beanC 顺利完成初始化,并将 beanA 从三级缓存移动到二级缓存中
  10. 随后 beanA 继续他的属性填充工作,此时也获取到了 beanC ,beanA 也随之完成了创建,回到 getSingleton()方法中继续向下执行,将 beanA 从二级缓存移动到一级缓存中
    在这里插入图片描述

五:Spring解决循环依赖一定需要三级缓存吗?

二级缓存也能解决循环依赖的问题,但是如果完全依靠二级缓存解决循环依赖,意味着当我们依赖了一个代理类的时候,就需要在Bean实例化之后完成AOP代理。而在Spring的设计中,为了解耦Bean的初始化和代理,是通过后置处理器来在Bean生命周期的最后一步来完成AOP代理的。Spring为了不破坏AOP的代理设计原则,则引入第三级缓存,在三级缓存中保存对象工厂,有了它,在后续发生循环依赖时,如果依赖的Bean被AOP代理,那么通过这个工厂获取到的就是代理后的对象,如果没有被AOP代理,那么这个工厂获取到的就是实例化的真实对象。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值