本专栏参考文献《Spring源码深度解析》
在对xml配置文件解析完成之后,开始进行bean加载。此过程十分复杂,大致流程如下:
- 转换对应beanName
- 尝试从缓存中加载单例
- bean的实例化
- 原型模式的依赖检查
- 检测parentBeanFactory
- 将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition
- 寻找依赖
- 针对不同的scope进行bean创建
- 类型装换
简述:
1.转换对应beanName:
AbstractoryBeanFactory.transformedBeanName(String name)
这里的入参可能是别名,也可能是FactoryBean,所以需要进行一系列的解析,解析内容包含如下几点:
- 去除FactoryBean的修饰符,例如:如果name="&aa",那么会首先去除&符号,使得name="aa"
- 取指定alias所表示的最终beanName,例如:别名A指向名称为B的bean则返回B;若别名A指向别名B,别名B指向名称为C的bean,则返回C
2.尝试从缓存中加载单例
单例在Spring的同一个容器内只会被创建一次,后续再获取bean,就直接从单例缓存中获取了。当然这里只是尝试加载,如果加载不成功则再次尝试从singletonFactories中加载。因为在创建单例Bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,在Spring中创建的bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光加入到缓存中,一旦下一个bean创建的时候需要依赖上一个bean则直接使用ObjectFactory
3.Bean的实例化
如果从缓存中得到了bean的原始状态,则需要对bean进行实例化。缓存中记录的只是最原始的bean状态,并不一定是我们最终想要的bean。例如:我们需要对工厂bean进行处理,那么这里得到的其实是工厂bean的初始状态,但是我们真正需要的是工厂bean中定义的factory-method方法中返回的bean,而getObjectForBeanInstance就是完成这个工作的。
4.原型模式的依赖检查
只有在单例情况下才会尝试解决循环依赖,如果存在A中有B的属性,B中有A的属性,那么当依赖注入的时候,就会产生当A还未创建完成的时候由于对于B的创建再次返回创建A,造成循环依赖,也就是isPrototypeCurrentlyInCreation(beanName)判断true
5.检测parentBeanFactory
如果缓存没有数据的话直接转到父类工厂上去加载了。如果当前加载的XML配置文件中不包含beanName所对应的配置,就只能到parentBeanFactory去尝试夹杂了,然后再递归调用getBean方法
6.将存储XML配置文件的GenericBeanDefinition转换为RootBeanDefinition
因为从XML配置未见中读取到的bean信息是存储在GenericBeanDefinition中的,但是所有的bean后续处理都是针对于RootBeanDefinition的,所以这里需要进行一个转换,转换的同时如果父类bean不为空的话,则会一并合并父类的属性。
7.寻找依赖
因为bean的初始化过程中很可能会用到某些属性,而某些属性很可能是动态配置的,并且配置成依赖于其他的bean,那么这个时候就有必要先加载依赖的bean,所以在spring的加载顺序中,在初始化某一个bean的时候首先会初始化这个bean所对应的依赖
8.针对不同的scope进行bean的创建
在spring中存在不同的Scope,默认使用singleton即单例,但是还有些其他的配置诸如prototype、request之类的,在这个步骤中spring会根据不同的配置进行不同的初始化策略。
9.类型转换
程序到这一步,返回bean后已经基本结束了,通常对该方法的调用参数requiredType是空的,但是可能会存在这一的情况,返回的bean其实是个String,但是requiredType却传入Integer类型,那么这时候本步骤就会起作用,它的功能是将返回的bean转换为requiredType所指定的类型。当然,String转换为Integer是最简单的一种转换,在Spring中提供了各种各样的转换器,用户也可以自己扩展转换器来满足需求。
几个关键类及数据结构:
Map<String,BeanDefinition> beanDefinitionMap:存放所有已经加载的类
AbstractBeanFactory: 该类的doGetBean()方法为bean加载的入口
ObjectFactory:
FactoryBean:
GernericBeanDefinition:存储XML配置文件
RootBeanDefinition: