一、Bean的生命周期
1.1.Bean生命周期相关知识
前置需要了解的知识,Bean的生命周期,需要了解请移步Bean的生命周期
二、使用一级缓存解决同一个类被多次创建的问题
2.1.无缓存Bean创建图解
@Component
public class BeanA {
@Autowired
private BeanB b;
}
@Component
public class BeanB {
@Autowired
private BeanA a;
}
在无缓存的情况下,我们看到BeanB创建了一个新的BeanA'注入,但是我们都知道Spring里面大部分的Bean都是单例的,不能创建出BeanA和BeanA'的情况,因此需要引入一级缓存,将创建好的BeanA给缓存起来方便使用。
2.2.同一个类不能创建多个Bean导致循环依赖的问题
由于BeanA没有创建完毕,在一级缓存中不存在,同时由于不能创建多个Bean,因此BeanB无法创建BeanA,BeanB的创建流程就因此中断。
总结:一级缓存的存在是为了解决同一个类被多次创建的问题,但是因此也存在循环依赖的问题。
三、使用二级缓存解决Bean循环依赖
3.1.二级缓存的使用图解
在实例化阶段的时候已经创建出A的对象了,只是没有填充A里面的属性,并非是完整的BeanA,一旦调用的对于的属性就会报错。但是似乎我们在bean创建的过程中并不需要调用其属性。那么我们如果我们能够提早引用非完整的BeanA,就能解决循环依赖的问题。
3.2.二级缓存存在的问题
当发生循环依赖,二级缓存命中,此时BeanB引用了非完整对象A,当BeanA完成了属性赋值和初始化后,BeanB引用的非完整BeanA就会变成完整的对象A。
但是若BeanA在属性赋值和初始的过程换了一个新的对象A' 作为BeanA,那么BeanB引用的非完整的对象A就是一个错误的BeanA。
四、使用三级缓存拒绝部分循环依赖
4.1.仅发生循环依赖
BeanA没有更换对象,不会报错
4.2.仅BeanA在属性赋值和初始化的过程更换对象
BeanA从对象A更换为对象A' 但是由于没有被引用到非完整BeanA(发生循环依赖),因此没有问题。
4.3.发生循环依赖的且BeanA在属性赋值和初始化的过程更换对象
BeanB引用了错误的对象A,Spring报循环依赖的错误。
五、Spring中的三级缓存
5.1.三级缓存
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
}
singletonObjects:缓存创建完成的bean
earlySingletonObjects:缓存仅仅做了实例化的bean,且被其他的bean依赖了的bean,即缓存了循环依赖的bean。
singletonFactories:缓存获取earlySingletonObjects工厂,实际上的意思是,缓存了缓存仅仅做了实例化的bean,但是没有被其他的bean依赖bean
earlySingletonObjects和singletonFactories两者都是缓存实例化阶段之后的bean,区别在于前置实例化完后,有其他的bean依赖了它,后者暂时还没有其他的bean依赖它
5.2.三级缓存中对象的获取
Spring需要一个bean(单例)时,或尝试先获取,如果没有,才会去创建,代码如下:
红框1是判断这个bean是否已经创建,如果已经创建就直接返回
红框2是创建bean的逻辑,即bean的生命周期那部分代码
我们来详细看看红框1的代码:
这部分代码的逻辑就是singletonObjects有就返回singletonObjects里面的,没有的就返回earlySingletonObjects里面的,没有就用singletonFactories获得一个earlySingletonObject,放到earlySingletonObjects里面去,同时移除singletonFactories里面的singletonFactory
所以Sping获取一个bean的顺序就是singletonObjects > earlySingletonObjects > singletonFactories#getObject > createBean
5.3.三级缓存中对象的添加与删除
5.3.1.singletonFactory的添加时机。
当bean实例化完后,添加singletonFactory的缓存 singletonFactory里面实际上存放的是实例化之后的bean,其添加到缓存中的时机在bean初始化结束的时候
从代码中,我们可以看到在bean实例化之后就会创建一个ObjectFactory放到singletonFactories中,ObjectFactory里面有一个方法getObject,getObject调用getEarlyBeanReference,getEarlyBeanReference实际上就是将实例化完的bean给返回
5.3.2.singletonFactory的删除时机。
当成为earlySingletonObject或singletonObject时删除。
5.3.3.earlySingletonObject的添加时机。
当发生循环依赖时,即获取完singletonFactory后删除singletonFactory添加earlySingletonObject。(如上面的流程图所示)
5.3.4.earlySingletonObject删除时机。
当bean创建完毕时删除
5.3.5.singletonObject添加时机。
当bean创建完毕时,删除earlySingletonObject,添加singletonObject