由上篇的分析可知,spring建立和实例化bean的过程的环节是比较多而且包装比较深的,那么若是每次getBean时都须要走这么多环节的话,那么不但会产生不少内存对象和计算逻辑,并且更重要的是没法解决对象在一些场景中的依赖问题,尤为是循环依赖的问题。所以spring自己也考虑到了这个问题,在建立bean的过程当中会有一些相关的缓存设计。今天咱们就一块儿来看一下它是如何用缓存来解决的。spring
场景一、首次getBean()时
首次获取bean时,根据上图的流程当从一级或二级缓存中获取,若拿到则直接返回。若没有则直接从三级缓存中拿,当三级缓存中有缓存对象时,则经过缓存的beanFactory .getObject()直接拿到bean, 同时移除三级缓存将拿到的bean写入二级缓存中,而后返回对象。
场景二、首次createBean()时
在doCreateBean()过程当中,若bean设置可提早暴露(默认开启),则会建立三级缓存(beanFactory对象)
为何会在建立三级缓存时,同时移除二级缓存?由于二级缓存中的对象是从三级缓存中获取的,因此当三级缓存更新时会同时移除老旧的二级缓存数据,避免产生缓存数据不一致问题。缓存
在A对象中,持有对B对象的引用;同理在B对象中,也支持对A对象的引用。这种循环依赖分两种状况:1.在A对象中,B对象做为A对象的成员变量;2.在A对象中,B对象做为A对象的构造参数依赖, 这两种方式一旦有相互成环的引用场景,就须要引发重视了。
以上截图属第一种状况,spring也只有对这种状况有考虑。这种状况spring视为正常引用,其它状况spring不支持且有此状况会直接抛出异常。ide
那么对于以上的第一种循环依赖状况,spring是如何解决的呢?经过构建三级缓存机制完美解决这个问题。具体的解决过程请看下面的流程图
根据上面的解决流程图和贴出的缓存源码, 详细的解释以下:函数
OK, 看到这里 你们是否是明白了?spring的三个等级的缓存机制设计是很值得玩味的。感兴趣的能够深刻去看下源码。
最后要明确一个结论:只有beandefintion的Scope=Singleton类型才能进行缓存和支持以上的第一种状况的循环依赖,其它类型的只要出现循环依赖,spring直接抛出异常。至于其它状况为何spring不支持你们看过源码,应该或多或少能想获得。设计
关于spring缓存和循环依赖的问题就先分享到这里。有什么关于这块的问题能够直接在评论区留言,更多spring源码的干货请继续关注!3d