Spring-源码-三级缓存面试题

下面说Spring的三级缓存

// 从上至下 分表代表这“三级缓存”
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); //一级缓存
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); // 二级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 三级缓存
...

// 这个缓存也十分重要:它表示bean创建过程中都会在里面呆着,它在Bean开始创建时放值,创建完成时会将其移出
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

// 当这个Bean被创建完成后,会标记为这个 注意:这里是set集合 不会重复。至少被创建了一次的  都会放进这里
private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));

实现循环依赖的原理

Spring的循环依赖的理论依据基于Java的引用传递,获得对象的引用时,对象的属性是可以延后设置的。

一、如果没有2级缓存,只有一级和三级的情况下,可以吗?

不可以,首先要明白,一次缓存的是完全实例化好的Bean,二级缓存是半成品,三级缓存是ObjectFactory
如果去掉了二级缓存,假设A依赖B,B依赖A,当实例化B的时候,发现三级缓存有A的ObjectFactory对象,然后拿到A的实例对象,拿完只有必须要保证其他依赖的Bean是一个实例,多次调用产生的对象肯定是不一样的(前提是A是AOP代理的Bean),所以一定要把A从三级转移出来,如果只有一级缓存,那么放里面肯定是不合适的。所以不能少二级缓存。

二、如果没有三级缓存,只有一级缓存和二级缓存,可以吗?

如果只是普通Bean之间的循环依赖是用不上三级缓存,只有AOP代理的Bean会用到三级缓存。
那么如果去掉三级缓存也是可以的,下面举个例子说明下。比如A和B都是需要AOP代理并且存到循环依赖的Bean。

流程:
1、先创建A的普通实例对象,在通过后置处理器来创建A的代理对象,此时A的代理对象还没有完成初始化完,所以要存到如二级缓存里面去,在去填充A里面的属性,发现有依赖B,此时去实例化B,
2、创建B普通实例对象,在通过后置处理器创建B的代理对象,B也没有完全实例完,所以存到二级缓存里面去,在去填充B里面的属性,发现依赖A,从二级缓存里面拿到A的代理对象赋值。到这里B的代理对象创建完成,并把B存到一级缓存里面,移除二级缓存中的B。在回到A的属性填充流程上。
3、此时A就可以拿B的代理对象,并完成填充,流程结束。

这么做可以但是站在性能上不合适,就是发现是AOP代理对象,直接生成然后再去实例化,不使用考虑懒加载的方式处理。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

信仰_273993243

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值