佛山免费建站平台,郑州服装网站建设公司,施工企业账务处理,注册安全工程师考试时间Spring框架为了解决循环依赖问题#xff0c;设计了一套三级缓存机制#xff1a;
一级缓存singletonObjects:这个是最常规的缓存#xff0c;用于存放完成初始化好的bean#xff0c;如果某个bean已经在这个缓存了直接返回。二级缓存earlySigletonObjects:这个用于存放早期暴…
Spring框架为了解决循环依赖问题设计了一套三级缓存机制
一级缓存singletonObjects:这个是最常规的缓存用于存放完成初始化好的bean如果某个bean已经在这个缓存了直接返回。二级缓存earlySigletonObjects:这个用于存放早期暴露出来的bean,就是那些创建出来还没有初始化好的bean这样做的目的就是为了bean创建过程中能提前暴露出来方便解决循环依赖的问题。三级缓存 singletonFactories:这个缓存存放的是bean的工厂对象这个工厂对象负责bean的实例当一个bean创建时它的工厂对象会被放入缓存中。
Spring解决循环依赖 三级缓存 singletonObjects用于存放完全初始化好的 bean从该缓存中取出的 bean 可以直接使用 earlySingletonObjects提前曝光的单例对象的cache存放原始的 bean 对象尚未填充属性用于解决循环依赖 singletonFactories单例对象工厂的cache存放 bean 工厂对象用于解决循环依赖
整体流程 首先A完成初始化第一步先将自己提前曝光出来(通过ObjectFactory将自己提前曝光出来)在初始化的时候发现自己需要依赖B,就开始尝试get(B),这时候发现B还没有创建 B走创建流程在B初始化的时候依赖C,C还没有创建出来 C开始初始化在C初始化的时候发现自己依赖A于是尝试get(A)这时候由于A已经添加到缓存中了一般都是添加到三级缓存中singletonFactory通过ObjectFactory提前曝光所以可以通过ObjectFactory#getObject()获取到A对象。C拿着A对象后顺利初始化,然后自己添加到一级缓存中 回到B,B也拿到C对象完成初始化A可以顺利拿到B这里整个链路已经完成初始化过程了。
关键字三级缓存提前曝光
再来一个例子
假设现在有两个bean一个A一个B;
Spring容器开始创建A对象会先去一级缓存中查看是否有BeanA的实例如果没有就会创建一个A的实例并将其工厂对象放入三级缓存中然后BeanA 的创建因为需要注入B而被挂起Spring开始创建BeanB对象。
BeanB同样回去一级缓存中查找是否存在B实例由于还没有创建Spring会将bean B的半成品放入二级缓存继续创建买这个B需要依赖A,由于A的工厂对象已经放在三级缓存中了spring可以直接获取三级对象中的beanA的工厂对象通过它来创建beanA的实例。
这样即使两个 beans 相互依赖Spring 也能够通过三级缓存机制成功地创建它们解决了循环依赖的问题。 仅有二级缓存无法解决涉及AOP代理的循环依赖问题。 为什么二级缓存不可以
二级缓存earlySingletonObjects用于存储半成品的Bean实例即那些已经被实例化但尚未完成初始化如属性填充和方法调用的Bean。这个缓存允许Spring在Bean的创建过程中就能提前暴露出来以便于解决循环依赖的问题。然而如果只有二级缓存当涉及到AOP代理时问题就来了。
AOP代理的生成是在Bean的初始化阶段完成的这意味着在Bean的所有属性都被设置之后。如果一个Bean需要被代理那么在代理之前Spring会尽量从缓存中获取到原始的Bean实例以避免在代理过程中出现循环引用的问题。但是如果只有二级缓存那么在Bean初始化之前我们无法从缓存中获取到代理对象因为二级缓存中存储的是尚未初始化的Bean实例而不是代理对象。
例子
假设有两个BeanA和B它们相互依赖并且A需要被AOP代理。在Spring的创建过程中首先会创建A的实例并将其放入二级缓存中。然后当尝试创建B并注入A时会发现A还没有完成初始化因此无法生成A的代理对象。这样就会导致循环依赖的问题无法被解决。
而三级缓存中的singletonFactories存储的是Bean的工厂对象可以在Bean初始化之前就生成代理对象并将其放入一级缓存singletonObjects中。这样即使Bean之间存在循环依赖Spring也能够通过三级缓存机制成功地创建它们解决了循环依赖的问题。
总的来说三级缓存机制是Spring为了在保持设计原则的同时解决循环依赖和AOP代理的问题而设计的。二级缓存虽然可以解决部分循环依赖的问题但在面对AOP代理时就显得力不从心了。因此Spring需要三级缓存来确保在复杂情况下依然能够正常工作。