- 前言
- 第一部分 核心实现
- 第 1 章 Spring 整体架构和环境搭建
- 第 2 章 容器的基本实现
- 第 3 章 默认标签的解析
- 第 4 章 自定义标签的解析
- 第 5 章 bean 的加载
- 第 6 章 容器的功能扩展
- 第 7 章 AOP
- 第二部分 企业应用
- 第 8 章 数据库连接 JDBC
- 第 9 章 整合 MyBatis
- 第 10 章 事务
- 第 11 章 SpringMVC
- 第 12 章 远程服务
- 第 13 章 Spring 消息
第 5 章 bean 的加载
经过前面的分析,我们终于结束了对 XML 配置文件的解析,接下来将会面临更大的挑战,就是对 bean 加载的探索。bean 加载的功能实现远比 bean 的解析要复杂得多,同样,我们还是以本书开篇的示例为基础,对于加载 bean 的功能,在 Spring 中的调用方式为:
MyTestBean bean=(MyTestBean) bf.getBean("myTestBean")
这句代码实现了什么样的功能呢?我们可以先快速体验一下 Spring 中代码是如何实现的。
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean
typeCheckOnly) throws BeansException {
//提取对应的 beanName
final String beanName = transformedBeanName(name);
Object bean;
/*
* 检查缓存中或者实例工厂中是否有对应的实例
* 为什么首先会使用这段代码呢,
* 因为在创建单例 bean 的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,
* Spring 创建 bean 的原则是不等 bean 创建完成就会将创建 bean 的 ObjectFactory 提早曝光
* 也就是将 ObjectFactory 加入到缓存中,一旦下个 bean 创建时候需要依赖上个 bean 则直接使用
ObjectFactory
*/
//直接尝试从缓存获取或者 singletonFactories 中的 ObjectFactory 中获取
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean
'" + beanName +
"' that is not fully initialized yet - a consequence of
a circular reference");
}
else {
beanName + "'");
logger.debug("Returning cached instance of singleton bean '" +
}
}
//返回对应的实例,有时候存在诸如 BeanFactory 的情况并不是直接返回实例本身而是返回指定方法返回的实例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}else {
//只有在单例情况才会尝试解决循环依赖,原型模式情况下,如果存在
//A 中有 B 的属性,B 中有 A 的属性,那么当依赖注入的时候,就会产生当 A 还未创建完的时候因为
//对于 B 的创建再次返回创建 A,造成循环依赖,也就是下面的情况
//isPrototypeCurrentlyInCreation(beanName) 为 true
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
BeanFactory parentBeanFactory = getParentBeanFactory();
//如果 beanDefinitionMap 中也就是在所有已经加载的类中不包括 beanName 则尝试从
parentBeanFactory 中检测
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
String nameToLookup = originalBeanName(name);
//递归到 BeanFactory 中寻找
if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
//如果不是仅仅做类型检查则是创建 bean,这里要进行记录
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
//将存储 XML 配置文件的 GernericBeanDefinition 转换为 RootBeanDefinition,如果指
定 BeanName 是子 Bean 的话同时会合并父类的相关属性
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
String[] dependsOn = mbd.getDependsOn();
//若存在依赖则需要递归实例化依赖的 bean
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
getBean(dependsOnBean);
//缓存依赖调用
registerDependentBean(dependsOnBean, beanName);
}
}
//实例化依赖的 bean 后便可以实例化 mbd 本身了
//singleton 模式的创建
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}else if (mbd.isPrototype()) {
//prototype 模式的创建(new)
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}else {
//指定的 scope 上实例化 bean
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope '"
+ scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
thread; " +
"Scope '" + scopeName + "' is not active for the current
"consider defining a scoped proxy for this bean if you
intend to refer to it from a singleton",
ex);
}
}
}
//检查需要的类型是否符合 bean 的实际类型
if (requiredType != null && bean != null && !requiredType.isAssignableFrom
(bean.getClass())) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type
[" +
ClassUtils.getQualifiedName(requiredType) + "]", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.
getClass());
}
}
return (T) bean;
}
仅从代码量上就能看出来 bean 的加载经历了一个相当复杂的过程,其中涉及各种各样的考虑。相信读者细心阅读上面的代码,并参照部分代码注释,是可以粗略地了解整个 Spring 加载 bean 的过程。对于加载过程中所涉及的步骤大致如下。
(1)转换对应 beanName。
或许很多人不理解转换对应 beanName 是什么意思,传入的参数 name 不就是 beanName 吗?其实不是,这里传入的参数可能是别名,也可能是 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。
从代码上看,如果缓存没有数据的话直接转到父类工厂上去加载了,这是为什么呢?
可能读者忽略了一个很重要的判断条件:parentBeanFactory != null && !containsBean Definition (beanName),parentBeanFactory != null。parentBeanFactory 如果为空,则其他一切都是浮云,这个没什么说的,但是!containsBeanDefinition(beanName) 就比较重要了,它是在检测如果当前加载的 XML 配置文件中不包含 beanName 所对应的配置,就只能到 parentBeanFactory 去尝试下了,然后再去递归的调用 getBean 方法。
(6)将存储 XML 配置文件的 GernericBeanDefinition 转换为 RootBeanDefinition。
因为从 XML 配置文件中读取到的 Bean 信息是存储在 GernericBeanDefinition 中的,但是所有的 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 中提供了各种各样的转换器,用户也可以自己扩展转换器来满足需求。
经过上面的步骤后 bean 的加载就结束了,这个时候就可以返回我们所需要的 bean 了,图 5-1 直观地反映了整个过程。其中最重要的就是步骤(8),针对不同的 scope 进行 bean 的创建,你会看到各种常用的 Spring 特性在这里的实现。
在细化分析各个步骤提供的功能前,我们有必要先了解下 FactoryBean 的用法。
图 5-1 bean 的获取过程
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论