探索Bean加载过程
1.BeanFactory类的getBean(String name);
AbstractBeanFactory重写了getBean(String name)方法;
public Object getBean(String name)throws BeansException{
return doGetBean(name, null, null, false);
}
查看源码:
仅从代码质量上就能看出来bean的加载经历了一个相当复杂的过程,其中涉及各种各样的考虑。相信读者细心月度上面的代码,并参照部分代码注释,是可以粗略地了解整个Spring加载bean的过程。对于加载过程汇总所涉及的步骤大致如下。
1.转换对应beanName。
或许很多不理解转换对应beanName是什么意思,传入的参数name不就是beanName吗?其实不是,这里传入的参数可能是别名,也可能是FactoryBean,所以需要进行一系列的解析,这些解析内容包括如下内容。
1> 去除FactoryBean的修饰符,也就是如果name="&aa", 那么会首先去除&而使name="aa"。
2> 取指定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
从代码上看,如果缓存没有数据的话直接转到父类工厂上去加载了,这是为什么呢?可能忽略了一个很重要的判断条件:parentBeanFactory != null && !containsBeanDefinition(beanName), parentBeanFactory != null 。 parentBeanFactory如果为空,则其他一切都是浮云,这个没什么说的,但是!containsBeanDefinition(beanName)就比较重要了,它是在检测如果当前加载的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,但是还有写其他的配置如property、request之类。在这个步骤中,Spring会根据不同的配置进行不同的初始化策略。
9.类型转换。
程序到这里返回bean后已经基本结束了,通常对该方法的调用参数requiredType是为空的,但是可能会存在这样的情况,返回的bean其实是个String,但是requiredType却传入Integer类型,那么这时候步骤就会起作用了,它的功能是将返回的bean转换为requiredType所指定的类型。当然,String转换为Integer是最简单的一种转换,在Spring中提供了各种各样的转换器,用户也可以自己扩展转换器来满足需求。
经过上面的步骤后bean加载就结束了,这个时候就可以返回我们所需要的bean了,其中最重要的步骤8,针对不同scope进行bean的创建,你会看到各种常用的Spring特性在这里的实现。
FactoryBean的使用
一般情况下,Spring通过反射机制利用bean的class属性指定实现类来实例化bean。