Spring循环依赖为什么需要三级缓存?

if (earlySingletonExposure) { //默认为true
	if (logger.isTraceEnabled()) { 
		logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
	}
    //把ObjectFactory存到三级缓存中,三级缓存中的Bean会被后置处理来增强:代理等
	addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); 
}
.....
//给创建好的对象每个属性进行赋值,@Autowired发生在这里
populateBean(beanName, mbd, instanceWrapper); 
//初始化bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
.....

说明:

  1. 上述代码是doCreateBean()里面的代码:首先默认将bean对应的ObjectFactory存入三级缓存中,然后属性赋值,初始化。
  2. 一级缓存存放成品bean的实例,二级缓存存放半成品bean,三级缓存存放ObjectFactory,可以在调用相应的方法时返回bean,其中二级缓存和三级缓存是专门来解决循环依赖的问题的。

原因:

  1. 解决循环依赖需要提前暴露半成品bean。
  2. 如果只有一级三级缓存,连半成品bean都没有,何从谈起解决循环依赖之说。
  3. 如果只有一级二级缓存,为了解决循环依赖,需要先将半成品bean存到二级缓存中暴露出来,但是又为了解决代理问题,暴露出来的bean还得是代理后的,所以需要此时(刚实例化bean后)就生成代理对象,否则:就会出现b中注入的a不是代理a的情况,但是spring设计之初是在bean初始化最后阶段代理,而不是在实例化后马上代理,所以加了三级缓存来延迟生成代理对象,这样只有在循环依赖这种情况下不得不用到bean的时候才生成代理bean并返回,没有循环依赖就不会生成代理bean,所以就保证了绝大多数情况还是会在初始化最后阶段生成代理对象。

总结:

其实笔者认为:spring用几级缓存无所谓,用几级都可以实现,只不过是spring做了一些取舍,最终用了三级,
如果把一二级缓存合成一个,#beanname表示成品bean,%beanname表示半成品bean,也是一样可以实现的,
只不过是丑陋、不太合理一点。

欢迎大家在评论区提出问题讨论,笔者看到会第一时间回复,如果觉得对你有帮助的话就点个赞吧。

    原文作者:程序员卢卡
    原文地址: https://blog.csdn.net/m0_46546381/article/details/124534149
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞