【Spring篇】Spring是如何解决循环依赖的?Bean的一、二、三级缓存是什么?

Spring是如何解决循环依赖的

在这里插入图片描述

1. 解决方案(setter注入)

用setter方法注入(非构造方法注入),且对于单例模式下的Bean

注意:如果是构造器注入引起的循环依赖,直接启动不了,无解

2. 关键词

Bean的生命周期(实例化属性赋值分开)、ObjectFactory、三级缓存

2. Spring解决循环依赖的过程

1. 现象

ClassA引用ClassB,ClassB中又引用了ClassA。

2. 解决步骤

  1. A的实例化,Spring选择合适的构造器实例化A,并把A的ObjectFactory放入到三级缓存

  2. A的属性赋值,赋值的过程中,发现成员变量B为被实例化,接着会去执行B的生命周期

  3. B的实例化,Spring选择合适的构造器实例化B,并将B的ObjectFactory放入到三级缓存

  4. B的属性赋值,赋值的过程中,发现成员变量A能够在三级缓存中找到(半成品),B属性赋值成功,删除二级、三级缓存中的Bean,保存到一级缓存中

  5. 回到A的属性赋值,A属性赋值成功(完成品),删除二级、三级缓存中的Bean,保存到一级缓存中

1. 问:这里第4步骤,属性B是如何找到A的半成品对象的
  1. 从三级缓存中取出Bean对应的ObjectFactory实例,调用其getObject方法,来获取早期曝光Bean,最终会调用getEarlyBeanReference方法

  2. 拿到半成品的bean实例(属性未填充),从三级缓存移除,放到二级缓存earlySingletonObjects

    注意:此时B注入的是一个半成品的实例A对象,不过随着B初始化完成后,A会继续进行后续的初始化操作,最终B会注入的是一个完整的A实例,因为在内存中它们是同一个对象

1. getEarlyBeanReference的作用

2种情况:

  1. 如果bean被AOP切面代理则返回的是beanProxy对象
  2. 如果未被代理则返回的是原bean实例
2. 问:为什么要用到二级缓存?(AOP代理的Bean)

好像只需要用到三级缓存就可以了,为什么要用到二级缓存?

1. bean被AOP进行了切面代理的场景

getEarlyBeanReference方法返回的是代理对象,还是被CGLIB代理的,每次执行都会产生一个新的代理对象

这就会有问题了,因为A是单例的,每次执行singleFactory.getObject()方法又会产生新的代理对象,假设这里只有一级和三级缓存的话,我每次从三级缓存中拿到singleFactory对象(也可以认为是ObjectFactory),执行getObject()方法又会产生新的代理对象,这是不行的,因为A是单例的,所有这里我们要借助二级缓存来解决这个问题,将执行了**singleFactory.getObject()**产生的对象放到二级缓存中去,后面去二级缓存中拿,没必要再执行一遍singletonFactory.getObject()方法再产生一个新的代理对象,保证始终只有一个代理对象

2. 二级缓存的作用

在Bean被AOP代理的情况下,保证始终只有一个代理对象

3. 总结

如果没有AOP的话确实可以两级缓存就可以解决循环依赖的问题,如果加上AOP,两级缓存是无法解决的,不可能每次执行singleFactory.getObject()方法都给我产生一个新的代理对象,所以需要借助另外一个缓存来保存产生的代理对象

参考一下优秀的文章:Spring 为何需要三级缓存解决循环依赖,而不是二级缓存

Spring中Bean的一级缓存、二级缓存、三级缓存

1. 一级缓存(初始化完成的Bean)singletonObjects

存在ConcurrentHashMap中,用来存放已经初始化完成的Bean

2. 二级缓存(有问题的Bean)earlySingletonObjects

存在HashMap中,存放半成品的Bean,一般处于循环引用的Bean才会暂时保存在这个缓存里

3. 三级缓存(存ObjectFactory)singletonFactories

存在HashMap中,存放ObjectFactory实例(用来获取Bean的工厂类)、在IoC容器中,所有刚被创建出来的ObjectFactory,默认都会保存到该缓存中。

1. 作用

spring会提前将已经实例化的bean通过ObjectFactory半成品暴露出去

半成品是指:bean对象已经实例化,但是未进行属性填充,是一个不完整的bean实例对象

4. 三者之间的关系

  1. 一级二级缓存中的Bean是互斥的,同一个Bean只可能存在其中一个缓存
  2. 二级缓存中保存的是BeanFactory产生的对象或AOP代理类对象
  3. 三级缓存只存工厂类,不存Bean实例
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值