简单了解三级缓存解决循环依赖

什么是循环依赖问题?

Spring框架有个特点就是大量使用缓存,当Spring需要某个bean对象的时候,它不会直接创建这个bean,而是会先从缓存里面找,如果缓存中没有才会创建这个bean对象,比如Person对象有个Car属性,当Person对象属性赋值的时候就会去容器(缓存)里面拿,那么如果Car对象又有个Person属性,就会不断地重复这个过程,Person获取Car,Car又获取Person,最终方法无限递归造成栈溢出

有什么办法进行属性赋值?

在Spring可以通过构造器或者set()方法进行属性赋值,又分为byName(如@Resource)或者byType(如@Autowired)。

Spring能够解决的只能解决单例beanset()方法注入的循环依赖。

单例bean和多例bean

Spring是用了三级缓存存放提前暴露的半成品bean

而对于多例bean,没有使用缓存所以当Spring遇到多例bean的循环依赖将会直接抛出异常

set()方法和构造器

set()方法是属性赋值使用的办法,配合反射实现

构造器在对象实例化的时候被调用,将会调用getBean属性赋值,但是这里赋值的时候不会加载三级缓存,就会报错

三级缓存解决循环依赖

有哪些缓存?

 // 一级缓存,beanName -> 实例化并且初始化的成品
 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
 ​
 // 二级缓存,beanName -> 实例化但是未初始化的成品
 private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
 ​
 // 三级缓存,beanName -> ObjectFactory
 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

缓存加入时机

一级缓存

在singletonObject = singletonFactory.getObject();创建完完整的单例bean实例之后会把这个单例bean加入到一级缓存。

二级缓存

this.earlySingletonObjects.put(beanName, singletonObject);把未完全初始化的bean从三级缓存提升到二级缓存。

三级缓存

在初始化之前,调用addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));把bean提前暴露到第三级缓存,防止循环依赖。

总结

其实本质上只有二级缓存,二级缓存提前暴露未完全初始化的单例bean,一级缓存是完整的单例bean,我们用二级缓存给属性赋值,而一级缓存来获取bean,如果有代理bean,那么就会造成beanA和b.属性beanA不同,那第三级缓存实际上是为了代理bean而存在的,我们需要通过第三层缓存SingletonFactory来生成代理对象,注意这里缓存是不能被替换的,只能够新增,所以采用多一级缓存才能对代理bean有效。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值