Spring的三级缓存
Spring中的三级缓存指的是bean的创建过程中的三个缓存阶段,分别是singletonObjects、earlySingletonObjects和singletonFactories。
- singletonObjects缓存(第一级缓存):保存完全初始化好的单例bean实例,这是默认的单例缓存。当从缓存中获取bean时,如果存在完全初始化好的bean,则直接返回。
- earlySingletonObjects缓存(第二级缓存):保存尚未完全初始化的单例bean实例,一般是因为该bean依赖其他尚未初始化的bean。当其他依赖的bean初始化完成后,Spring会完成该bean的剩余初始化工作。
- singletonFactories缓存(第三级缓存):保存用于创建单例bean的ObjectFactory。在Spring创建bean时,如果发现bean的创建工厂实现了ObjectFactory接口,就会把该工厂实例保存到singletonFactories缓存中。当需要获取该bean时,Spring会调用该工厂的getObject()方法创建bean实例。
需要注意的是,这些缓存仅在单例作用域下有效,对于prototype作用域的bean则没有缓存。
Spring解决循环依赖问题的实现原理
Spring循环依赖的实现原理是通过使用三级缓存解决循环依赖问题。当Bean创建过程中发现循环依赖时,Spring会将正在创建的Bean包装成ObjectFactory,并放入早期对象缓存中。同时,Spring会创建一个空的Bean实例,也放入第一级缓存中。在Bean创建的过程中,如果需要依赖循环依赖的Bean,则通过ObjectFactory获取该Bean的代理对象,并注入到当前Bean中,从而完成依赖注入。当该Bean创建完成后,将其放入第二级缓存中,等待后续的处理。当所有Bean创建完成后,Spring会遍历第二级缓存中的Bean,并调用其postProcessAfterInitialization方法进行后置处理。在后置处理完成后,Bean将被放入第三级缓存中,以备后续需要。通过这种方式,Spring能够在创建Bean的过程中解决循环依赖问题。
为什么用三级缓存,而不是二级缓存
Spring使用三级缓存而不是二级缓存来解决循环依赖的问题,是因为二级缓存只能缓存已经完全初始化的Bean,而对于循环依赖的情况,需要在Bean创建的过程中就能够获取到代理对象,并注入到当前Bean中。而在Bean创建的过程中,Bean实例还没有完全初始化完成,此时如果将Bean放入二级缓存中,会出现状态不一致的情况,从而无法正确处理循环依赖问题。因此,Spring引入了第一级缓存,用于存放正在创建的Bean实例,以便在创建Bean的过程中能够及时获取到代理对象。同时,Spring引入了第三级缓存,用于存放Bean创建完成后的实例,以提高后续获取Bean实例的效率。通过使用三级缓存,Spring能够在Bean创建的过程中解决循环依赖问题,并保证Bean实例状态的一致性。
哪些循环依赖问题Spring解决不了
- 构造函数循环依赖:如果两个或多个 bean 之间存在构造函数循环依赖,即它们相互依赖于它们的构造函数参数,那么 Spring就无法解决这个循环依赖问题。
- 原型模式(prototype)循环依赖:如果两个原型模式的 bean 之间相互依赖,则 Spring无法解决它们之间的循环依赖问题。
- 非单例的代理对象循环依赖:如果一个 bean 依赖于一个非单例的代理对象,而这个代理对象又依赖于该bean,那么 Spring 无法解决它们之间的循环依赖问题。