spring如何解决循环依赖的,三级缓存的原理是什么。相信这些问题大家或多或少都听过,今天的主要问题是为什么是三级缓存,两级不行吗?大多数的回答是因为aop要生成代理对象,这个回答在我看来只是一个表面原因。
要回答这个问题应该从spring bean的生命周期入手:
循环依赖发生的位置是在第二步,spring的做法是在第一步完成之后,放了一个ObjectFactory在第三级缓存中:
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
注意这个lambad,只有调用ObjectFactory的方法的时候才会调用getEarlyBeanReference。
回到主题,当在第二步填充属性的时候如果没有循环依赖,刚才放到第三级缓存的ObjectFactory也就没有用;如果发生了循环依赖,这个时候还不能直接用此时只完成第一步的bean作为被填充的属性,因为原始的bean后边还可能会生成代理对象,这样就和注入的bean不是一个对象了。这个时候就会调用这个ObjectFactory的方法,最终到getEarlyBeanReference方法。
getEarlyBeanReference这个方法会去生成一个代理对象,但是这个时候这个对象还没有完成spring bean生命周期的第二步,就去完成后边的几步,破坏了生命周期的一个顺序。
回到一开始的问题,两级缓存能解决循环依赖问题吗?我的答案是能解决,不考虑生命周期这些东西,把现在bean初始化的第二步放到第九步后边,也就是先生成代理对象,放到第二级缓存中,然后再去填充属性,如果发生了循环依赖,直接在二级缓存中能拿到最终的代理对象,没有必要去弄一个三级缓存出来。我们能想明白,spring的开发者肯定也能想明白,但是为什么没有这么做呢?
参考这篇文章的补充https://blog.csdn.net/u012098021/article/details/107352463
斗胆猜测,spring是先有生命周期这玩意的,后来才发现有循环依赖这个bug,这个时候不能去把之前定义好的东西给推翻吧,就像咱们写代码的时候发现一个bug就去把之前的流程全都改了,不太符合我们摸鱼的本性吧。
而且spring也不太想让我们去使用循环依赖,这不在高版本的spring boot中就不再支持循环依赖了,而且就算现在也不是每个循环依赖spring都给你解决的,像@Aysnc和@Validated这些都不给你兜底了。原因简单来说就是getEarlyBeanReference生成代理对象的时候就不考虑你这俩注解(详情可以看:https://fangshixiang.blog.csdn.net/article/details/92797058)。
所以说我来下个无法证实的结论,三级缓存只是为了解决循环依赖又不想破坏生命周期的顺序一种妥协(当然循环依赖的时候还是破坏了)