建议浏览顺序从Day 1 开始。
1 Bean的声明周期
Spring Bean的生命周期是从 Bean 实例化之后,即通过反射创建出对象之后,到Bean成为一个完整对象,最终存储到单例池中,这个过程被称为Spring Bean的生命周期。Spring Bean的生命周期大体上分为三个阶段:
Bean 实例化阶段:Spring 框架会取出BeanDefinition的信息进行判断当前Bean的范围是否是Singleton的是否是延迟加载的,是否是FactoryBean,最终将一个普通改的singleton的Bean通过反射进行实例化。总结来说就是对BeanDeifinition进行解析,然后实例化对象
Bean的初始化阶段:Bean创建之后仅仅是一个"半成品",还需要对Bean的实例的熟悉进行填充,执行一些Aware接口方法、执行BeanPostProcessor方法、执行InitializingBean接口的初始化方法、执行自定义初始化init方法。该阶段是Spring最具技术含量和复杂度的阶段,Aop增强功能,后面要学习的Spring的注解功能等spring高频面试题Bean的循环引用问题都是在这个阶段体现的;
总结来说就是:在实例化后,通过执行一些Aware接口方法、执行BeanPostProcessor方法、执行InitializingBean接口的初始化方法、执行自定义初始化init方法(相当于初始化方法),对bean进行填充。
Bean的完成阶段:经过初始化阶段,Bean就成为了一个完整的Spring Bean,被存储到单例池singletonObjects中去了,即完成了Spring Bean的整个生命周期。
Spring Bean的初始化过程涉及如下几个过程
Bean实例的属性填充,在xml标签配置
Aware接口属性注入,实现接口
BeanPostProcessor的before()方法回调, 后处理器。
InitializingBean接口的初始化方法回调,实现接口
自定义初始化方法init回调,自定义然后通过xml配置
BeanPostProcessor的after()方法回调,后处理器
PS:通过代码验证上述初始化顺序.......
Spring在进行属性注入时,会分为如下几种情况:
注入普通属性,String、int或存储基本类型的集合时,直接通过set方法的反射设置进去
注入单向对象引用属性时,从容器中getBean获取后通过set方法反射设置进去,如果容器中没有,则先创建被注入对象Bean实例(完成整个生命周期)后,在进行注入操作;
注入双向对象引用属性时,就比较复杂了,涉及了循环引用(循环依赖)问题,下面会详细阐述解决方案
重点在于双向注入循环引用问题:
UserService里面有set方法放入UserDao
UserDao里面有set方法放入UserService
重点可以打断最后的红线,将UserService的半成品存入map,UserDao先找SingletonObjects,没有找到然后找map(多级缓存)。
解决方案:
Spring提供了三级缓存存储完整Bean实例和半成品Bean实例,用于解决循环引用问题
在DefaultListableBeanFactory的上四级父类DefaultSingletonBeanRegistry中提供如下三个Map:
/** Cache of singleton objects: bean name to bean instance. */
// 1. 一级缓存,最终存储单例Bean成品容器,即实例化和初始化完成的Bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 2. 二级缓存,存储单例Bean半成品容器,且当前对象已经被其他对象引用了
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
//3. 三级缓存,单例Bean的工厂池,存储半成品,对象未被引用,使用时通过工厂创建Bean
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
UserService和UserDao循环依赖的过程结合上述三级缓存描述一下
UserService 实例化对象,但尚未初始化,将UserService存储到三级缓存;
UserService 属性注入,需要UserDao,从缓存中获取,没有UserDao;
UserDao实例化对象,但尚未初始化,将UserDao存储到到三级缓存
UserDao属性注入,需要UserService,从三级缓存获取UserService,UserService从三级缓存移入二级缓存;
UserDao执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存
UserService 注入UserDao;
UserService执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存
Spring IoC 整体流程总结
从读取xml-> beanDefinition->beanDefinitionMap->bean实例化->bean初始化->进入SingletonObjects中。