Bean的加载
Spring Ioc容器就是以某种方式加载配置文件并创建相应的对象进行绑定形成一个可取可存的容器。
spring在实现过程中分为两个阶段:
- 容器初始化阶段
- 加载bean阶段
容器初始化阶段
- 通过某种方式(ResourceLoadle)将配置文件(Resource)加载
- 通过BeanDefinitionReader将配置文件转换为BeanDefinition
- 通过BeanDefinitionRegistry将BeanDefinition注册到容器中
- Ioc容器开始进行初始化
加载bean阶段
- 调用**BeanFactory.getBean(…)**进行bean加载
- 初始化Bean完成之后进行缓存或原型模式
doGetBean(…)方法
**doGetBean(…)**方法是bean加载的核心方法,主要有以下几个流程:
核心流程
- 对BeanName的处理
通过对传入的beanName进行处理获取到真实的beanName
- 尝试从已加载的容器中获取
如果容器中已经存在bean,那么就直接进行返回
- 对原型模式循环依赖的检查
- 尝试通过ParentBeanFacoty返回bean
- 标记bean正在进行创建
- 处理循环依赖
通过标记 beanName -> 依赖的beanNames,递归进行判断是否存在递归关系;如果存在递归关系 -> 处理循环依赖
- 不同作用域下的实例化
createBean(…)
- 对返回结果进行类型转化
循环依赖
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
- 属性依赖
- 加载A类,尝试从缓存或正在加载的集合中获取,由于第一次初始化肯定是取不到的
- 由于缓存中没有bean,A类进行初始化
- A类初始化完成需要装配属性,装配属性的时候发现依赖的B还未进行加载,就执行加载B类的动作
- B类重复1,2,3,在执行3时,发现依赖于A,那么就将会从正在执行的加载Map对象中去获取A类
- B类加载成功->A类继续加载
- @DependsOn
@DependsOn是指定其他bean要在当前bean初始化之前进行加载;并且不能有循环依赖的场景出现
- A类依赖于B类,A类初始化到这里时会去加载B类,
- 如果B类依赖于A类,那么就会先调用一次getBean(“A”),这里是不要求有返回结果
bean初始化的细节
Singleton scope
- 再次检查缓存中是否有bean
- 初始化bean的前置处理
- **singletonFactory.getObject();**初始化bean
- 初始化bean的后置处理
- 放入缓存及处理
5.1 【put】singletonObjects 属性,单例 bean 的缓存。
5.2 【remove】singletonFactories 属性,单例 bean Factory 的缓存。
5.3 【remove】earlySingletonObjects 属性,“早期”创建的单例 bean 的缓存。
5.4 【add】registeredSingletons 属性,已经注册的单例缓存。
prototype scope
- 初始化bean的前置处理
- **createBean();**初始化bean
- 初始化bean的后置处理
总结
Bean的加载的加载主要分为两个大流程:
- 容器环境的初始化
1.1 资源文件加载
1.2 资源文件 -> BeanDefinition
1.3 注册BeanDefinition
2.Bean的初始化
2.1 对注册的BeanDefinition的再次处理(属性合并、加载顺序等)
2.2 加载Bean(解决循环依赖、前置后置操作、初始化bean)