Java Spring Bean的生命周期 三级缓存
SpringBean的生命周期:是从 Bean 实例化之后(即通过反射创建出对象之后),到Bean成为一个完整对象,最终存储到单例池中,这个过程被称为Spring Bean的生命周期。Spring Bean的生命周期大体上分为三个阶段:
- 实例化阶段:Spring框架会取出BeanDefinition的信息进行判断当前Bean的范围是否是singleton的,是否不是延迟加载的,是否不是FactoryBean等,最终将一个普通的singleton的Bean通过反射进行实例化
- 初始化阶段:Bean创建之后还仅仅是个"半成品",还需要对Bean实例的属性进行填充、执行一些Aware接口方法、执行BeanPostProcessor方法、执行InitializingBean接口的初始化方法、执行自定义初始化init方法等
- 存储阶段:经过初始化阶段,Bean就成为了一个完整的Spring Bean,被存储到单例池singletonObjects中去了,即完成了Spring Bean的整个生命周期
Bean的实例化链接:Bean的实例化
Bean后处理器链接:Bean后处理器
Bean的初始化阶段:
- Bean实例的属性填充
- Aware接口属性注入
- BeanPostProcessor的before()方法回调
- InitializingBean接口的初始化方法回调
- 自定义初始化方法init回调
- BeanPostProcessor的after()方法回调
Spring在进行属性注入时,会分为如下几种情况:
- 注入普通属性,String、int或存储基本类型的集合时,直接通过set方法的反射设置进去;
- 注入单向对象引用属性时,从容器中getBean获取后通过set方法反射设置进去,如果容器中没有,则先创建被注入对象Bean实例(完成整个生命周期)后,在进行注入操作;
- 注入双向对象引用属性时,就比较复杂了,涉及了循环引用(循环依赖)问题,下面会详细阐述解决方案。
Spring循环依赖和三级缓存
当Object1中需要属性注入Object2,Object2也需要属性注入Object1,将Object1和Object2都交给Spring管理时,Spring初始化Bean过程中,假如先初始化Object1,Spring发现需要依赖注入Object2,就会从singletonObjects中去getBean()尝试获取Object2,此时Object2并没有初始化,所以获取不到,那么Object1的初始化挂起,先进行Object2的初始化,又发现了Object2需要依赖注入Object1,此时Object1初始化挂起,并没有实际初始化结束存储到singletonObjects中,所以又去尝试初始化Object1,这就出现循环依赖闭环注入的问题,如下所示
为了解决循环依赖的问题,Spring提供了三级缓存来存储不同初始化完成度的Bean实例
- singletonObjects/一级缓存:存储单例Bean成品,即初始化完成的Bean实例
- earlySingletonObjects/二级缓存:存储早期Bean单例池缓存半成品对象,且当前对象已经被其他对象引用了
- singletonFactories/三级缓存:缓存半成品对象,对象未被引用,使用时在通过工厂创建Bean
还是上述的问题,有了三级缓存就能解决,当Object2从三级缓存中获取到了Object1的引用,那么Object2就可以当作Object1初始化成功,进而完成自己的初始化