Spring 系列教程之 bean 的加载

2022-10-16,,,,

Spring 系列教程之 bean 的加载

经过前面的分析,我们终于结束了对 XML 配置文件的解析,接下来将会面临更大的挑战,就是对 bean 加载的探索。bean 加载的功能实现远比 bean 的解析要复杂得多,同样,我们还是以本书开篇的示例为基础,对于加载 bean 的功能,在 Spring 中的调用方式为

Mytestbean bean=(Mytestbean) bf getbean("mytest Bean")

这句代码实现了什么样的功能呢?我们可以先快速体验一下 Spring 中代码是如何实现的。

org.springframework.beans.factory.support.AbstractBeanFactory

public <T> T getBean(String name, Class<T> requiredType, Object... args) throws BeansException {
return doGetBean(name, requiredType, args, 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
*/
// 直接尝试从缓存获取或者 singletonFactor⊥es 中的 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 {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 返回对应的实例,有时候存在诸如 Beanfactory 的情况并不是直接返回实例本身面是返回指定方法返回的实例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} else {
// 只有在单例情况才会尝试解决环依赖,原型模式情况下,如果存在
// A中有B的属性,B中有A的属性,那么当依注入的时候,就会产生当A还未创建完的时候因为
// 对于B的创建再次返创建A,造成循环依赖,也就是下面的情况了
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 {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
} // 如果还是仅仅做类型检查则是创建 bean,这里要进行记录
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
} try {
// 将存储 XML 配置文件的 GernericBeanDefinition 转换为 RootBeanDefinition,如果指定 BeanName 是子 Bean 的话同时会合并父类的相关属性
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args); // 若存在依赖则需要递归实例化依赖的 bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
if (isDependent(beanName, dependsOnBean)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'");
}
registerDependentBean(dependsOnBean, beanName);
getBean(dependsOnBean);
}
} // 实例化依赖的 bean 后便可以实例化 mbd 本身了,singleton 模式的创建
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) {
// prototype 模式的创建
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 name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
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,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw 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)判断 ture

(5) 检测 parentBeanFactory

从代码上看,如果缓存没有数据的话直接转到父类工厂上去加载了,这是为什么呢?可能读者忽略了一个很重要的判断条件: parentBeanFactory != null && !containsBeanDefinition(beanName)。parentBeanFactory 如果为空,则其他一切都是浮云,这个没什么说的,但是 !containsBeanDefinition(beanName) 就比较重要了,它是在检测如果当前加载的 XML 配置文件中不包含 beanName 所对应的配置,就只能到 parentBeanFactory 去尝试下了,然后再去递归的调用 getBean 方法。

(6) 将存储 XML 配置文件的 GemericBeanDefinition 转换为 RootBeanDefinition

因为从 XML 配置文件中读取到的 Bean 信息是存储在 GemericBeanDefinition 中的,但是所有的 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 了,其中最重要的就是步骤(8),针对不同的 scope 进行 bean 的创建,你会看到各种常用的 Spring 特性在这里的实现。

在细化分析各个步骤提供的功能前,我们们有必要先了解下 FactoryBean 的用法。

5.1 FactoryBean 的使用

一般情况下,Spring 通过反射机制利用 bean 的 class 属性指定实现类来实例化 bean。在某些情况下,实例化 bean 过程比较复杂,如果按照传统的方式,则需要在 <bean> 中提供大量的配置信息,配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring 为此提供了一个org.springframework.bean.factory.FactoryBean 的工厂类接口,用户可以通过实现该接口定制实例化 bean 的逻辑。

FactoryBean 接口对于 Spring 框架来来说占有重要的地位,Spring 自身就提供了70多个 FactoryBean 的实现。它们隐藏了实例化一些复杂 bean 的细节,给上层应用带来了便利。从 Spring3.0开始, FactoryBean 开始支持泛型,即接口声明改为 FactoryBean 的形式:

package org.springframework.beans.factory;

public interface FactoryBean {
T getObject() throws Exception;
Class<\?> getObjectType();
boolean isSingleton();
}

在该接口中还定义了以下3个方法:

(1) T getObject():返回由 Factory Bean创建的bean实例,如果 isSingleton() 返回 true,则该实例会放到 Spring 容器中单实例存池中

(2) boolean isSingleton():返回由 FactoryBean 创建的 bean 实例的作用域是 singleton 还是 prototype

(3) Class<?> getObjectType():返回 FactoryBean 创建的 bean 类型。

当配置文件中的 class 属性配置的实现类是 FactoryBean 时,通过 getBean() 方法返回的不是 FactoryBean 本身,而是 FactoryBean#getObject() 方法所返回的对象,相当于 FactoryBean#getObject() 代理了 getBean() 方法。例如:如果使用传统方式配置下面 Car 的 时,Car 的每个属性分别对应一个 元素标签。

public class Car {
private String brand;
private int maxSpeed;
private Double price;
// get/set
}

如果用 FactoryBean 的方式实现就会灵活一些,下例通过逗号分割符的方式一次性地为 Car 的所有属性指定配置值:

public class CarFactoryBean implements FactoryBean<Car> {
private String carInfo; @Override
public Car getObject() throws Exception {
Car car=new Car();
String[]infos = carInfo.split(","); car.setBrand(infos[0]);
car.setMaxSpeed(Integer.parseInt(infos[1]));
car.setPrice(Double.parseDouble(infos[2])); return car;
} @Override
public Class<?> getObjectType() {
return null;
} @Override
public boolean isSingleton() {
return false;
} public String getCarInfo(){
return carInfo;
} public void setCarInfo(String carInfo){
this.carInfo=carInfo;
}
}

有了这个 CarFactoryBean 后,就可以在配置文件中使用下面这种自定义的配置方式配置 Car Bean 了

<bean id="car" class="spring.factory_bean.CarFactoryBean">
<property name="carInfo" value="红旗CA72,200,20000.00"/>
</bean>

当调用 getBean("car") 时,Spring 通过反射机制发现 CarFactoryBean 实现了 FactoryBean 的接口,这时 Spring 容器就调用接口方法 CarFactoryBean#getObject() 方法返回。如果希望获取 CarFactoryBean 的实例,则需要在使用 getBean(beanName) 方法时在 beanName 前显示的加上 & 前缀,例如 getBean("&car")

5.2 缓存中获取单例 bean

介绍过 FactoryBean 的用法后,我们就可以了解 bean 加载的过程了。前面已经提到过,单例在 Spring 的同一个容器内只会被创建一次,后续再获取 bean 直接从单例缓存中获取,当然这里也只是尝试加载,首先尝试从缓存中加载,然后再次尝试从 singletonFactories 中加载。因为在创建单例 bean 的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,Spring 创建 bean 的原则是不等 bean 创建完成就会将创建 bean 的 ObjectFactory 提早曝光加入到缓存中,一旦下一个 bean创建时需要依赖上个 bean,则直接使用 ObjectFactory

public Object getSingleton(String beanName) {
// 参数 true 设置标识允许时期依赖
return getSingleton(beanName, true);
} protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 检查缓存中是否存在实例
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 如果此时 bean 正在加载则不处理
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 当某些方法需要提前初始化的时候则会调用 addSingletonFactory 方法
// 将对应的 ObjectFactory 初始化策略存储在 singletonFactories
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 调用预先设定的 getObject 方法
singletonObject = singletonFactory.getObject();
// 记录在缓存中,earlySingletonObjects 与 singletonFactories 互斥
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

这个方法因为涉及循环依赖的检测,以及涉及很多变量的记录存取,所以让很多读者摸不着头脑。这个方法首先尝试从 singletonObjects 里面获取实例,如果获取不到再从 earlySingletonObjects 里里面获取,如果还获取不到,再尝试从 singletonFactories 里面获取 beanName 对应的 ObjectFactory,然后调用这个 ObjectFactory 的 getobject来创建bean,并放到 earlySingletonObjects 里面去,并且从 earlySingletonObjects 里面 remove 掉这个 ObjectFactory,而对于后续的所有内存操作都只为了循环依赖检测时候使用,也就是在 allowEarlyReference 为 true 的情况下才会使用。

这里涉及用于存储 bean 的不同的 map,可能让读者感到崩溃,简单解释如下:

    singletonObjects:用于保存 BeanName 和创建 bean 实例之间的关系,beanName->beanInstance

    singletonfactories:用于保存 Beanname 和创建 bean 的工厂之间的关系,beanName->Objectfactory

    earlySingletonObjects:也是保存 BeanName 和创建 bean 实例之间的关系,与 singletonObjects 的不同之处在于,当一个单例 bean 被放到这里面后,那么当 bean 还在创建过程中,就可以通过 getBean 方法获取到了,其目的是用来检测循环引用。

    registeredsingletons:用来保存当前所有已注册的 bean

5.3 从 bean 的实例中获取对象

在 getBean 方法中, getObjectForBeanInstance 是个高频率使用的方法,无论是从缓存中获得 bean还是根据不同的 scope 策略加载 bean。总之,我们得到 bean的实例后要做的第一步就是调用这个方法来检测一下正确性,其实就是用于检测当前 bean 是否是 FactoryBean 类型的 bean,如果是,那么需要调用该 bean 对应的 FactoryBean 实例中的 getObject() 作为返回值。

无论是从缓存中获取到的 bean 还是通过不同的 scope 策略加载的 bean 都只是最原始的 bean 状态,并不一定是我们最终想要的 bean。举个例子,假如我们需要对工厂 bean 进行处理,那么这里得到的其实是工厂 bean 的初始状态,但是我们真正需要的是工厂 bean中定义的 factory-method 方法中返回的 bean,而 getObjectForBeanInstance() 方法就是完成这个工作的。

protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) { // 如果指定的 name 是工厂相关(以&为前缀)且 beanInstance 又还是 FactoryBean 类型则验证不通过
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
} // 现在有了 bean 实例,这个实例可能为正常的 bean 或者是 FactoryBean
// 如果是 FactoryBean 则用它创建实例,但是如果用户想要直接获取工厂实例
// 而不是工厂的 getObject 方法对应的实例,那么传入的 name 应该加入前缀 &
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
} // 加载 FactoryBean
Object object = null;
if (mbd == null) {
// 尝试从缓存中加载 bean
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// containsBeanDefinition 检测 beanDefinitionMap 中也就是在所有已经加载的类中检测是否定义 beanName
if (mbd == null && containsBeanDefinition(beanName)) {
// 将存储 XML 配制文件的 GernericBeanDefinition 转化为 RootBeanDefinition
// 如果指定 BeanName 是子 Bean 的话同时会合并父类的相关属性
mbd = getMergedLocalBeanDefinition(beanName);
}
// 是否是用户定义的而还是应用程序本身定义的
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}

从上面的代码来看,其实这个方法并没有什么重要的信息,大多是些轴助代码以及一些功能性的判断,而真正的核心代码却委托给了 getObjectFromFactoryBean,我们来看看 getObjectForBeanInstance 中的所做的工作。

(1) 对 FactoryBean 正确确性的验证。

(2) 对非 FactoryBean不做任何处理

(3)对 bean 进行转换。

(4)将从 Factory 中解析 bean 的工作委托给 getObjectFromFactoryBean

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName,
boolean shouldPostProcess) {
// 单例
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (object != null && shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
}
this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
}
}
return (object != NULL_OBJECT ? object : null);
}
}
else {
// 非单例
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (object != null && shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}

很遗憾,在这个代码中我们还是没有看到想要看到的代码,在这个方法里只做了一件事情,就是返回的bean 如果是单例的,那就必须要保证全局唯一,同时,也因为是单例的,所以不必重复创建,可以使用缓存来提高性能,也就是说已经加载过就要记录下来以便于下次复用,否则的话就直接获取了。

在 doGetObjectFromFactoryBean 方法中我们终于看到了我们想要看到的方法,也就是 object = factory.getObject() ,是的,就是这句代码,我们的历程犹如剥洋葱一样,一层一层的直到最内部的代码实现,虽然很简单。

private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory,
final String beanName) throws BeanCreationException { Object object;
try {
// 需要权限验证
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
return factory.getObject();
}
}, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
// 直接调用 getObject 方法
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
} // Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null && isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
return object;
}

上面我们已经讲述了 FactoryBean 的调用方法,如果 bean 声明为 FactoryBean 类型,则当提取bean时提取的并不是 FactoryBean,而是 FactoryBean 中对应的 getObject 方法返回的 bean,而 doGetObjectFromFactoryBean 正是实现这个功能的。

但是,我们看到在上面的方法中除了调用 object = factory.getObject() 得到我们想要的结果后并没有直接返回,而是接下来又做了些后处理的操作,这个又是做什么用的呢?于是我们跟踪进入 AbstractAutowireCapableBeanFactory 类的 postProcessObjectFromFactoryBean 方法:

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
return applyBeanPostProcessorsAfterInitialization(object, beanName);
} public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException { Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessAfterInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}

对于后处理器的使用我们还未过多接触,后续章节会使用大量篇幅介绍,这里,我们只需了解在在 Spring 获取 bean 的规则中有这样一条:尽可能保证所有 bean 初始化后都会调用注册的 BeanPostProcessor 的 postProcessAfterInitialization 方法进行处理,在实际开发过程中大可以针对此特性设计自己的业务逻辑。

5.4 获取单例之前

我们讲解了从缓存中获取单例的过程,那么,如果缓存中不存在已经加载的单例 bean 就需要从头开始 bean的加载过程了,而 Spring 中使用 getSingleton 的重载方法 getSingleton(beanName, singletonFactory) 实现 bean 的加载过程。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "'beanName' must not be null");
// 全局变量需要同步
synchronized (this.singletonObjects) {
// 首先检查对应的 bean 是否已经加载过
// 因为 singleton 模式其实就是复用已创建的 bean,所以这一步是必须的
Object singletonObject = this.singletonObjects.get(beanName);
// 进行 singleton 的 bean 的初始化
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while the singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<Exception>();
}
try {
// 初始化 bean
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 加入缓存
addSingleton(beanName, singletonObject);
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}

上述代码中其实是使用了回调方法,使得程序可以在单例创建的前后做一些准备及处理操作,而真正的获取单例 bean 的方法其实并不是在此方法中实现的,其实现逻辑是在 ObjectFactory类型的实例 singletonFactory 中实现的。而这些准备及处理操作包括如下内容:

(1) 检查缓存是否已经加载过

(2) 若没有加载,则记录 beanName 的正在加载状态。

(3) 加载单例前记录加载状态。可能你会觉得 beforeSingletonCreation 方法是个空实现,里面没有任何逻辑,但其实不是,这个函数中做了一个很重要的操作:记录加载状态,也就是通过 this.singletonsCurrentlyInCreation.add(beanName) 将当前正要创建的 bean 记录在缓存中,这样便可以对循环依赖进行检测。

protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) &&
!this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}

(4) 通过调用参数传入的 ObjectFactory 的个体 Object 方法实例化 bean

(5) 加载单例后的处理方法调用。同步骤(3)的记录加载状态相似,当 bean加载结東后需要移除缓存中对该 bean 的正在加载状态的记录。

protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) &&
!this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}

(6) 将结果记录至缓存并删除加载 bean 过程中所记录的各种辅助状态。

protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}

(7) 返回处理结果。

虽然我们已经从外部了解了加载 bean 的逻辑架构,但现在我们还并没有开始对 bean 加载功能的探索,之前提到过,bean 的加载逻辑其实是在传入的 ObjectFactory 类型的参数singletonFactory 中定义的,我们反推参数的获取,得到如下代码:

sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
}
});

ObjectFactory 的核心部分其实只是调用了 createBean 的方法,所以我们还需要到 createBean 方法中追寻真理。

5.5 准备创建 bean

我们不可能指望在一个函数中完成一个复杂的逻辑,而且我们跟踪了这么多 Spring 代码,经历了这么多函数,或多或少也发现了一些规律:一个真正干活的函数其实是以 do 开头的,比如 doGetObjectFromFactoryBean;而给我们错觉的函数,比如 getObjectFromFactoryBean,其实只是从全局角度去做些统等的工作。这个规则对于 createBean 也不例外,那么让我们看看在 createBean 函数中做了哪些准备工作。

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args)
throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd; // 锁定 class,根据设置的 class 属性或者根据 className 来解析 Class
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
} // 验证及准备覆盖的方法
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
} try {
// 给 BeanPostProcessors 一个机会来返回代理来替代真正的实例
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
} Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}

从代码中我们可以总结出函数完成的具体步骤及功能:

(1) 根据设置的 class 属性或者根据 className 来解析 Class

(2) 对 override 属性进行标记及验证。

很多读者可能会不知道这个方法的作用,因为在 Spring 的配置里面根本就没有诸如 override-method 之类的配置,那么这个方法到底是干什么用的呢?

其实在 Spring 中确实没有 override-method 这样的配置,但是如果读过前面的部分,可能会有所发现,在 Spring 配置中是存在 lookup-method 和 replace-method 的,而这两个配置的加载其实就是将配置统一存放在 BeanDefinition 中的 methodOverrides属性里,而这个函数的操作其实也就是针对于这两个配置的。

(3) 应用初始化前的后处理器,解析指定 bean 是否存在初始化前的短路操作。

(4) 创建 bean

我们首先查看下对 override 属性标记及验证的逻辑实现。

5.5.1 处理 override属性

查看源码中 AbstractBeanDefinition 类的 prepareMethodOverrides 方法:

public void prepareMethodOverrides() throws BeanDefinitionValidationException {
// Check that lookup methods exists.
MethodOverrides methodOverrides = getMethodOverrides();
if (!methodOverrides.isEmpty()) {
for (MethodOverride mo : methodOverrides.getOverrides()) {
prepareMethodOverride(mo);
}
}
}
protected void prepareMethodOverride(MethodOverride mo)
throws BeanDefinitionValidationException {
// 获取对应类中对应方法名的个数
int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
if (count == 0) {
throw new BeanDefinitionValidationException(
"Invalid method override: no method with name '" + mo.getMethodName() +
"' on class [" + getBeanClassName() + "]");
}
else if (count == 1) {
// 标记 MethodOverride 暂未被覆盖,避免参数类型检查的开销
mo.setOverloaded(false);
}
}

通过以上两个函数的代码你能体会到它所要实现的功能吗?之前反复提到到过,在 Spring 配置中存在 lookup-method 和 replace-method 两两个配置功能,而这两个配置的加载其实就是将配置统一存放在 BeanDefinition 中的 methodOverrides 属性里,这两个功能实现原理其实是在 bean 实例化的时候如果检测到存在 methodOverrides 属性,会动态地为当前 bean 生成代理并使用对应的拦截器为 bean 做增强处理,相关逻辑实现在 bean 的实例化部分详细介绍。

但是,这里要提到的是,对于方法的匹配来讲,如果一个类中存在若干个重载方法,那么,在函数调用及增强的时候还需要根据参数类型进行匹配,来最终确认当前调用的到底是哪个函数。但是, Spring 将一部分匹配工作在这里完成了,如果当前类中的方法只有一个,那么就设置重载该方法没有被重载,这样在后续调用的时候便可以直接使用找到的方法,而不需要进行方法的参数匹配验证了,而且还可以提前对方法存在性进行验证,正可谓一箭双雕。

5.5.2 实例化的前置处理

在真正调用 doCreate 方法创建 bean 的实例前使用了这样一个方法 resolveBeforelnstantiation(beanname,mbd) 对 BeanDefinigiton 中的属性做些前置处理。当然,无论其中是否有相应的逻辑实现我们都可以理解,因为真正逻辑实现前后留有处理函数也是可扩展的一种体现,但是,这并不是最重要的,在函数中还提供了一个短路判断,这才是最为关键的部分。

if (bean != null) {
return bean;
}

当经过前置处理后返回的结果如果不为空,那么会直接略过后续的的 Bean 的创建而直接返回结果。这一特性虽然很容易被忽略,但是却起着至关重要的作用,我们熟知的的 AOP 功能就是基于这里的判断的。

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
// 如果尚未被解析
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}

此方法中最吸引我们的无疑是两个方法 applyBeanPostProcessorsBeforeInstantiation 以及applyBeanPostProcessorsAfterInitialization 。两个方法实现的非常简单,无非是对后处理理器中的所有 InstantiationAwareBeanPostProcessor 类型的后处理器进行 postProcessBeforeInstantiation 方法和 BeanPostProcessor 的 postProcessAfterInitialization 方法的调用。

1.实例化前的后处理器应用

bean 的实例化前调用,也就是将 Absract Beandefinition转换为 Bean Wrapper前的处理。给子类一个修改 Beandefinition的机会,也就是说当程序经过这个方法后,bean可能已经不是我们认为的bean了,而是或许成为了一个经过处理的代理bean,可能是通过 cglib生成的,也可能是通过其它技术生成的。这在第第7章中会详细介绍,我们只需要知道,在bean的实例化前会调用后处理器的方法进行处理

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass,
String beanName) throws BeansException { for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}

2.实例化后的后处理器应用

在讲解从缓存中获取单例 bean 的时候就提到过, Spring 中的规则是在 bean的初始化后尽可能保证将注册的后处理器的 postProcessAfterInitialization 方法应用到该bean 中,因为如果返回的 bean 不为空,那么便不会再次经历普通 bean的创建过程,所以只能在这里应用后处理器的 postProcessAfterInitialization 方法。

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean,
String beanName) throws BeansException { Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessAfterInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}

5.6.1 什么是循环依赖

循环依赖就是循环引用,就是两个或多个 bean 相互之间的持有对方,比如 CircleA 引用 CircleB,CircleB 引用 CircleC, CircleC 引用 CircleA ,则它们最终反映为一个环。此处不是循环调用,循环调用是方法之间的环调用,如图5-2所示。

循环调用是无法解决的,除非有终结条件,否则就是死循环,最终导致内存溢出错误。

5.6.2 Spring 如何解决循环依赖

Spring 容器循环依赖包括构造器循环依赖和 setter 循环依依赖,那 Spring 容器如何解决循环依赖呢?首先让我们来定义循环引用类:

public class TestA {

    private TestB testB;

    public void a() {
testB.b();
}
public TestB getTestB() {
return testB;
} public void setTestB(TestB testB) {
this.testB = testB;
}
} public class TestB { private TestC testC; public void b() {
testC.c();
} public TestC getTestC() {
return testC;
} public void setTestC(TestC testC) {
this.testC = testC;
}
} public class TestC { private TestA testA; public void c() {
testA.a();
} public TestA getTestA() {
return testA;
} public void setTestA(TestA testA) {
this.testA = testA;
}
}

在 Spring 中将循环依赖的处理分成了3种情况。

1. 构造器循环依赖

表示通过构造器注入构成的循环依赖,此依赖是无法解决的,只能抛出 BeanCurrentlyInCreationException 异常表示循环依赖。

如在创建 TestA 类时,构造器需要 TestB 类,那将去创建 TestB,在创建 TestB 类田时又发现需要 TestC 类,则则又去创建 TestC,最终在创建 TestC 时发现又需要 TestA ,从而形成一个环,没办法创建。

Spring 容器将每一个正在创建的 bean 标识符放在一个 "当前创建bean池" 中,bean 标识符在创建过程中将一直保持在这个池中,因此如果在创建 bean 过程中发现自己已经在 "当前创建bean池" 里时,将抛出 BeanCurrentlyInCreationException 异常表示循环依赖;而对于创建完毕的 bean 将从 "当前创建bean池" 中清除掉我们通过一个直观的测试用例来进行分析。

(1) 创建配置文件

<bean id="testA" class="spring.depend_on.TestA">
<constructor-arg index="0" ref="testB"/>
</bean>
<bean id="testB" class="spring.depend_on.TestB">
<constructor-arg index="0" ref="testC"/>
</bean>
<bean id="testC" class="spring.depend_on.TestC">
<constructor-arg index="0" ref="testA"/>
</bean>

(2) 创建测试用例

@Test(expected = BeanCurrentlyInCreationException.class)
public void test() throws Throwable {
try {
new ClassPathXmlApplicationContext("depend-on-test.xml", DependOnTest.class);
} catch (Exception e) {
Throwable el = e.getCause().getCause().getCause();
throw el;
}
}

针对以上代码的分析如下:

    Spring 容器创建 "testA" bean,首先去 "当前创建bean池" 查找是否当前 bean正在创建,如果没发现,则继续准备其需要的枸造器参数 "testB",并将将 "testA" 标识放到 "当前创建bean池"。

    Spring 容器创建 "testB" bean,首先去 "当前创建bean池" 查找是否当前 bean正在创建,如果没发现,则继续准备其需要的枸造器参数 "testC",并将 "testB" 标识符放到 "当前创建bean池"

    Spring 容器创建 "testC" bean,首先去 "当前创建bean池" 查找是否当前 bean正在创建,如果没发现,则继鲯准备其需要的枸造器参数 "testA",并将 "testC" 标识符放到 "当前创建Bean池"。

    到此为止 Spring 容器要去创建 "testA" bean,发现该 bean 标识苻在 "当前创建bean池" 中,因为表示循环依赖,拋出 BeanCurrentlyInCreationException。

2. setter 循环依赖

表示通过 setter 注入方式构成的循环依赖。对于 setter 注入造成的依赖是通过 Spring 容器提前暴露刚完成构造器注入但未完成其他步骤(如setter注入)的 bean来完成的,而上且只能解决单例作用域的 bean循环依依赖。通过提前暴露一个单例工厂方法,从而使其他 bean 能引用到该 bean ,如下代码所示:

addSingletonFactory(beanName, new ObjectFactory() {
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});

具体步骤如下:

(1) Spring 容器创建单例 "testA" bean,首先根据无参构造器创建 bean,并暴露一个 "ObjectFactory" 用于返回一个提前暴露一个创建中的 bean,并将 "testA" 标识符放到 "当前创建bean池",然后进行 setter 注入 "testB"。

(2) Spring 容器创建单例 "testB" bean,首先根据无参构造器创建 bean,并暴露一个 "ObjectFactory" 用于返回一个提前暴露一个创建中的 bean,并将 "testB" 标识符放到 "当前创建bean池",然后进行 setter 注入 "testC"。

(3) Spring 容器创建单例 "testC" bean,首先根据无参构造器创建 bean,并暴露一个 "ObjectFactory" 用于返回一个提前暴露一个创建中的 bean,并将 "testC" 标识符放到 "当前创建bean池",然后进行 setter 注入 "testA"。进行注入 "testA" 时由于提前暴露了 "ObjectFactory" 工厂,从而使用它返回提前暴露一个创建中的 bean。

(4) 最后在依赖注入 "testB" 和 "testA",完成 setter 注入。

3. prototype 范围的依赖处理

对于 "prototype" 作用域bean,Spring 容器无法完成依赖注入,因为 Spring 容器不进行缓存 "prototype" 作用域的 bean,因此无法提前暴露一个创建中的 bean。示例如下:

(1)创建配置文件

<bean id="testA" class="spring.depend_on.TestA" scope="prototype">
<property name="testB" ref="testB"/>
</bean>
<bean id="testB" class="spring.depend_on.TestB" scope="prototype">
<property name="testC" ref="testC"/>
</bean>
<bean id="testC" class="spring.depend_on.TestC" scope="prototype">
<property name="testA" ref="testA"/>
</bean>

(2) 创建测试用例

@Test(expected = BeanCurrentlyInCreationException.class)
public void protorypeTesta() throws Throwable {
try {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("depend-on-prototype.xml", DependOnTest.class);
System.out.println(context.getBean("testA"));
} catch (Exception e) {
Throwable el = e.getCause().getCause().getCause();
throw el;
}
}

对于 "singleton" 作用域 bean,可以通过 setallowcircularreferences(false) 来禁用循环引用。

感谢互联网时代,让我可以方便地获取我想要的各种信息,当初我刚开始学习的时候,直纠结于这里错综复杂的逻辑,幸好我看到了一篇文章解开了我心中的疑惑。在此,感谢原作者,并将原文与大家分享,帮助大家更好的理解 Spring 的依赖,大家可以从 http://www.iflym.com/index.php/code/201208280001.html 来获取原文。

5.7 创建 ban

介绍了循环依賴以及 Spring 中的循环依赖的处理方式后后,我们继续 5.4 小节的内容。当经历过 resolveBeforeInstantiation 方法后,程序有两个选择,如果创建了代理或者说重写了 InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation 方法并在方法 postProcessBeforeInstantiation 中改变了 bean,则直接返回就可以了,否则需要进行常规 bean 的创建。而这常规 bean 的创建就是在 doCreateBean 中完成的。

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// 根据指定 bean 使用对应的策略创建新的实例,
// 如:工厂方法、构造函数自动注入、简单初始化
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null); // Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
mbd.postProcessed = true;
}
} // 是否需要提早曝光:单例&允许循环依赖&当前 bean 正在创建中,检测循环依赖
boolean earlySingletonExposure = (mbd.isSingleton() &&
this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 为避免后期循环依赖,可以在 bean 初始化完成前将创建实例的 ObjectFactory 加入工厂
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
// 对 bean 再一次依赖引用,主要应用 SmartInstantiationAware BeanPostProcessor
// 其中我们熟知的 AOP 就是在这里将 advice 动态织入 bean 中,若没有则直接返回 bean,不做任何处理
return getEarlyBeanReference(beanName, mbd, bean);
}
});
} // Initialize the bean instance.
Object exposedObject = bean;
try {
// 对 bean 进行填充,将各个属性值注入,其中,可能存在依赖于其他 bean 的属性,则会递归初始依赖 bean
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
// 调用初始化方法,如 init-method
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
} if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
// earlySingletonReference 只有在检测到有循环依赖的情况才不会为空
if (earlySingletonReference != null) {
// 如果 exposedObject 没有在初始化方法中被改变,也就是没有被增强
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
// 检测到依赖
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
// 因为 bean 创建后其所依赖的 bean 一定是已经创建的
// actualDependentBeans 不为空则表示当前 bean 创建后其依赖的 bean 却没有全部创建完,也就是说存在循环依赖
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
} // Register bean as disposable.
try {
// 根据 scopse 注册 bean
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
} return exposedObject;
}

尽管日志与异常的内容非常重要,但是在阅读源码的时候似乎大部分人都会直接忽略掉。在此不深人探讨日志及异常的设计,我们看看整个函数的概要思路。

(1) 如果是是单例则需要首先清除缓存。

(2) 实例化 bean,将 BeanDefinition 转换为 BeanWrapper。

转换是一个复杂的过程,但是我们可以尝试概括大致的功能,如下所示。

如果存在工厂方法则使用工厂方法进行初始始化。

一个类有多个构造函数,每个构造函数都有不同的参数,所以需要根据参数锁定构造方法并进行初始化。

如果既不存在工厂方法也不存在带有参数的构造函数,则使用默认的构造函数进行 bean 的实例化。

(3) applyMergedBeanDefinitionPostProcessors 的应用。

bean 合并后的处理,Autowired 注解正是通过此方法实现诸如类型的预解析。

(4) 依赖处理。

在 Spring 中会有循环依赖的情况,例如,当A中含有B的属性,而B中又含有A的属性时就会构成一个循环依赖,此时如果A和B都是单例,那么在 Spring中的处理方式就是当创建B的时候,涉及自动注入A的步骤时,并不是直接去再次创建A,而是通过放入缓存中的Objectfactory来创建实例,这样就解决了循环依赖的问题。

(5) 属性填充。将所有属性填充至bean的实例中。

(6) 循环依赖检查。

之前有提到过,在 Sping 中解决循环依赖只对单例有效,而对于 prototype 的 bean,Spring没有好的解决办法,唯一要做的就是抛出异常。在这个步骤里面会检测已经加载的 bean 是否已经出现了依赖循环,并判断是否需要抛出异常。

(7) 注册 DisposableBean

如果配置了 destroy-method,这里需要注册以便于在销毁时候调用。

(8) 完成创建并返回。

可以看到上面的步骤非常的繁琐,每一步骤都使用了大量的代码来完成其功能,最复杂也是最难以理解的当属循环依赖的处理,在真正进入 doCreateBean 前我们有必要先了解下循环依赖。

5.7.1 创建bean的实例

当我们了解了循环依赖以后就可以深入分析创建 bean 的每个步骤了,首先我们从 createBeanInstance 开始。

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// 解析 class
Class<?> beanClass = resolveBeanClass(mbd, beanName); if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
} // 如果工厂方法不为空则使用工厂方法初始化策略
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
} // Shortcut when re-creating the same bean...
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
// 一个类有多个构造函数,每个构造函数都有不同的参数,所以调用前需要先根据参数锁定构造函数或对应的工厂方法
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
} // 如果已经解析过则使用解析好的构造函数方法不需要再次锁定
if (resolved) {
if (autowireNecessary) {
// 构造函数自动注入
return autowireConstructor(beanName, mbd, null, null);
}
else {
// 使用默认的无参构造函数
return instantiateBean(beanName, mbd);
}
} // 需要根据参数解析构造函数
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() ==
RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
// 构造函数自动注入
return autowireConstructor(beanName, mbd, ctors, args);
} // 使用默认的无参构造函数
return instantiateBean(beanName, mbd);
}

虽然代码中实例化的细节非常复杂,但是在 createBeanlntance 方法中中我们还是可以清晰地看到实例化的逻辑的。

(1) 如果在 RootBeanDefinition 中存在 factoryMethodName 属性,或者说在配置文件中配置了 factory-method,那么 Spring 会尝试使用 instantiateUsingFactoryMethod(beanName, mbd, args) 方法根据 RootBeanDefinition 中的配置生成 bea n的实例。

(2) 解析构造函数并进行构造函数的实例化。因为一个 bean 对应的类中可能会有多个构造函数,而每个构造函数的参数不同, Spring 在根据参数及类型去判断最终会使用哪个构造函数进行实例化。但是,判断的过程是个比较消耗性能的步骤,所以采用缓存机制,如果已经解析过则不需要重复解析而是直接从 RootBeanDefinition 中的属性 resolvedConstructorOrFactoryMethod 缓存的值去取,否则需要再次解析,并将解析的结果添加至 RootBeanDefinition 中的属性resolvedConstructorOrFactoryMethod 中。

1. autowireConstructor

对于实例的创建 Spring 中分成了两种情况,一种是通用的实例化,另一种是带有参数的实例化。带有参数的实例化过程相当复杂,因为存在着不确定性,所以在判断对应参数上做了大量工作。

2. instantiateBean

经历了带有参数的构造函数的实例构造,相信你会非常轻松愉快地理解不带参数的构造函数的实例化过程。

protected BeanWrapper instantiateBean(final String beanName,
final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
return getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
}, getAccessControlContext());
}
else {
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}

你会发现,此方法并没有什么实质性的逻辑,带有参数的实例构造中,Spring 把精力都放在了构造函数以及参数的匹配上,所以如果没有参数的话那将是非常简单的一件事,直接接调用实例化策略进行实例化就可以了。

3.实例化策略

实例化过程中反复提到过实例化策略,那这又是做什么用的呢?其实,经过前面的分析,我们已经得到了足以实例化的所有相关信息,完全可以使用最简单的反射方法直接反射来构造实例对象,但是 Spring 却并没有这么做。

org.springframework.beans.factory.support.SimpleInstantiationStrategy

public Object instantiate(RootBeanDefinition bd, String beanName,
BeanFactory owner) {
// 如果有需要覆盖或者动态替换的方法则当然需要使用 cglib 进行动态代理,因为可以在创建代理的同时将动态方法织入类中
// 但是如果没有需要动态改变的方法,为了方便直接反射就可以了
if (bd.getMethodOverrides().isEmpty()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() {
@Override
public Constructor<?> run() throws Exception {
return clazz.getDeclaredConstructor((Class[]) null);
}
});
}
else {
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Exception ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(bd, beanName, owner);
}
}

看了上面两个函数后似乎我们已经感受到了 Spring 的良苦用心以及为了能更方便地使用 Spring而做了大量的工作。程序中,首先判断如果 beanDefinition.getMethodOverrides() 为空也就是用户没有使用 replace 或者 lookup 的配置方法,那么直接使用反射的方式,简单快捷,但是如果使用了这两个特性,在直接使用反射的方式创建实例就不妥了,因为需要将这两个配置提供的功能切人进去,所以就必须要使用动态代理的方式将包含两个特性所对应的逻辑的拦截增强器设置进去,这样才可以保证在调用方法的时候会被相应的拦截器增强,返回值为包含拦截器的代理实例。对于拦截器的处理方法非常简单,不再详细介绍,如果读者有兴趣,可以仔细研读第7章中关于 AOP 的介绍,对动态代理方面的知识会有更详细地介绍。

5.7.2 记录创建 bean 的 ObjectFactory

在 doCreate 函数中有这样一段代码:

// 是否需要提早曝光:单例&允许循环依赖&当前 bean 正在创建中,检测循环依赖
boolean earlySingletonExposure = (mbd.isSingleton() &&
this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 为避免后期循环依赖,可以在 bean 初始化完成前将创建实例的 ObjectFactory 加入工厂
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
// 对 bean 再一次依赖引用,主要应用 SmartInstantiationAware BeanPostProcessor
// 其中我们熟知的 AOP 就是在这里将 advice 动态织入 bean 中,若没有则直接返回 bean,不做任何处理
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}

这段代码不是很复杂,但是很多人不是太理解这段代码的作用,而且,这段代码仅从此函数中去理解也很难弄懂其中的含义,我们需要从全局的角度去思考 Spring 的依赖解决办法。

    earlySingletonExposure 从字面的意思理解就是提早曝光的单例,我们暂不定义它的学名叫什么,我们感兴趣的是有哪些条件影响这个值

    mbd.isSingleton() 没有太多可以解释的,此 RootBeanDefinition 代表的是否是单例。

    this.allowCircularReferences() 是否允许循环依賴,很抱,并没有找到在配置文件中如何配五,但是在 AbstractRefreshableApplicationContext 中提供了设置函数,可以通过硬编码的方式进行设置或者可以通过自定义命名空间进行配置,其中硬编吗的方式代码如下:

    Classpathmlapplicationcontext bf = new lasspathmlapplicationcontext (aspecttestxm");
    ibf. setallowbeandefinitionoverriding(false);

    isSingletonCurrentlyInCreation(beanName) 该 bean 是否在创建中。在 Spring 中,会有个专门的属性默认为 DefaultSingletonBeanRegistry 的 singletonsCurrentlyInCreation 来记录 bean 的加载状态,在 bean 开始创建前会将 beanName 记录在属性中,在 bean 创建结束后会将 beanName 从属性中移除。那么我们跟随代码一略走来可是对这个属性的记录并没有多少印象,这个状态是在哪里记录的呢?不同 scope 的记录位置并不一样,我们以 singleton 为例,在 singleton 下记录属性的函数是在 DefaultSingletonBeanRegistry 类的 public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) 函数的 beforeSingletonCreation(beanName) 和 afterSingletonCreation(beanName) 中,在这两段函数中分别 this.singletonsCurrentlyInCreation.remove(beanName) 与 this.singletonsCurrentlyInCreation.remove(beanName) 来进行状态的记录与移除。

经过以上分析我们了解变量 earlySingletonExposure 是否是单例、是否允许循环依赖、是否对应的 bean 正在创建的条件的综合。当这3个条件都满足时会执行 addSingletonFactory 操作,那么 addSingletonFactory 的作用是什么呢?又是在什么时候调用呢?

我们还是以最简单 AB 循环依赖为例,类 A 中含有属性类 B,而类 B 中又会含有属性类 A,那么初始化 bean 的过程如图5-3所示:

图5-3中展示了创建 bean 的流程,图中我们看到,在创建 A 的时候首先会记录类 A 所对应的 beanName,并将 bean 的创建工厂加入缓存中,而在对 A 的属性填充也就是调用 populate 方法的时候又会再一次的对 B 进行递归创建。同样的,因为在 B 中同样存在 A 属性,因此在实例化 B 的的 populate 方法中又会再次地初始化 B,也就是图形的最后,调用 getBean(A)。关键是在这里,有心的同学可以去找找这个代码的实现方式,我们之前已经讲过,在这个函数中并不是直接去实例化 A,而是先去检测缓存中是否有已经创建好的对应的 bean,或者是否已经创建好的 ObjectFactory,而此时对于 A 的 ObjectFactory 我们早已经创建,所以便不会再去向后执行,而是直接调用 ObjectFactory 去创建 A。这里最关键的是 ObjectFactory 的实现。

addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
// 对 bean 再一次依赖引用,主要应用 SmartInstantiationAware BeanPostProcessor
// 其中我们熟知的 AOP 就是在这里将 advice 动态织入 bean 中,若没有则直接返回 bean,不做任何处理
return getEarlyBeanReference(beanName, mbd, bean);
}
});

其中 getEarlyBeanReference 代码如下:

protected Object getEarlyBeanReference(String beanName,
RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
if (exposedObject == null) {
return exposedObject;
}
}
}
}
return exposedObject;
}

在 getEarlyBeanReference 函数中并没有太多的逻辑处理,或者说除了后处理器的调用外没有别的处理工作,根据以上分析,基本可以理清 Spring 处理循环依賴的解决办法,在 B 中创建依赖 A 时通过 ObjectFactory 提供的实例化方法来中断 A 中的属性填充,使 B 中持有的 A 仅仅是刚刚初始化并没有填充任何属性的 A,而这正初始化 A 的步骤还是在最开始创建 A 的时候进行的,但是因为 A 与 B 中的 A 所表示的属性地址是一样的,所以在 A 中创建好的属性填充自然可以通过 B 中的 A 获取,这样就解决了循环依赖的问题。

5.7.3 属性注入

在了解循环依赖的时候,我们曾经反复提到了 populateBean 这个函数,也多少了解了这个函数的主要功能就是属性填充,那么究竟是如何实现填充的呢?

protected void populateBean(String beanName, RootBeanDefinition mbd,
BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues(); if (bw == null) {
if (!pvs.isEmpty()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// 没有可填充的属性
return;
}
} // 给 InstantiationAwareBeanPostProcessors 最后一次机会在属性设置前来改变 bean
// 如:可以用来支持属性注入的类型
boolean continueWithPropertyPopulation = true; if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 返回值为是否继续填充
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
} // 如果后处理器发出停止填充命令则终止后续的执行
if (!continueWithPropertyPopulation) {
return;
} if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs); // 根据名称自动注入
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
} // 根据类型自动注入
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
} pvs = newPvs;
} // 后处理器已经初始化
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 需要检查依赖
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE); if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 对所有需要依赖检查的属性进行后处理
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
// 依赖检查,对应 depends-on 属性,3.0已经试用此属性
checkDependencies(beanName, mbd, filteredPds, pvs);
}
} // 将属性应用到 bean 中
applyPropertyValues(beanName, mbd, bw, pvs);
}

在 populateBean 函数中提供了这样的处理流程:

(1) InstantiationAwareBeanPostProcessor 处理器的 postProcessAfterInstantiation 函数的应用,此函数可以控制程序是否继续进行属性填充

(2) 根据注入类型(byName/byType),提取依赖的 bean,并统一存人 PropertyValues 中。

(3) 应用 InstantiationAwareBeanPostProcessor 处理器的 postProcessPropertyValues 方法,对属性获取完毕填充前对属性的再次处理,典型应用是 RequiredAnnotationBeanPostProcessor 类中对属性的验证

(4) 将所有 PropertyValues 中的属性填充至 BeanWrapper 中。

在上面的步骤中有几个地方是我们比较感兴趣的,它们分别是依赖注入(autowireByname/autowirebyType)以及属性填充,那么,接下来进一步分析这几个功能的实现细节。

1. autowireByName

上文提到根据注入类型(byName/byType),提取依赖的 bean,并统一存人 PropertyValue 中,那么我们首先了解下 byName 功能是如何实现的。

protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) { // 寻找 bw 中需要依赖注入的属性
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
if (containsBean(propertyName)) {
// 递归初始化相关的 bean
Object bean = getBean(propertyName);
pvs.add(propertyName, bean);
// 注册依赖
registerDependentBean(propertyName, beanName);
if (logger.isDebugEnabled()) {
logger.debug("Added autowiring by name from bean name '" + beanName +
"' via property '" + propertyName + "' to bean named '" + propertyName + "'");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
"' by name: no matching bean found");
}
}
}
}

如果读者之前了解了 autowire 的使用方法,相信理解这个函数的功能不会太困难,无非是在传入的参数 pws 中找出已经加载的 bean,并递归实例化,进而加入到 pvs 中。

2. autowireByType

autowireByType 与 autowireByName 对于我们理解与使用来说复杂程度都很相似,但是其实现功能的复杂度却完全不一样。

protected void autowireByType(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) { TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
} Set<String> autowiredBeanNames = new LinkedHashSet<String>(4);
// 寻找 bw 中需要依赖注入的属性
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
try {
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
// Don't try autowiring by type for type Object: never makes sense,
// even if it technically is a unsatisfied, non-simple property.
if (Object.class != pd.getPropertyType()) {
// 探测指定属性的 set 方法
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
boolean eager = !PriorityOrdered.class.isAssignableFrom(bw.getWrappedClass());
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
// 解析指定 beanName 的属性所匹配的值,并把解析到的存储在 autowiredBeanNames 中,染发发在多个封装 bean 时如
// @Autowired private List<A> aList; 将会找到所有匹配A类型的 bean 并将其注入
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
pvs.add(propertyName, autowiredArgument);
}
for (String autowiredBeanName : autowiredBeanNames) {
// 注册依赖
registerDependentBean(autowiredBeanName, beanName);
if (logger.isDebugEnabled()) {
logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" +
propertyName + "' to bean named '" + autowiredBeanName + "'");
}
}
autowiredBeanNames.clear();
}
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
}
}
}

实现根据名称自动匹配的第一步就是寻找 bw 中需要依赖注入的属性,同样对于根据类型动匹配的实现来讲第一步也是寻找 bw 中需要依赖注入的属性,然后遍历这些属性并寻找类型匹配的 bean,其中最复杂的就是寻找类型匹配的 bean。同时, Spring 中提供了对集合的类型注入的支持,如使用注解的方式:

@Autowired
private List<Test> tests;

Spring 将会把所有与 Test 匹配的类型找出来并注人到 tests 属性中,正是由于这一因素,所以在 autowireByType 函数中,新建了局部遍历 autowiredBeanNames

,用于存储所有依赖的 bean,如果只是对非集合类的属性注入来说,此属性并无用处。

对于寻找类型匹配的逻辑实现封装在了 resolveDependency 函数中。

org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency

public Object resolveDependency(DependencyDescriptor descriptor, String beanName,
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException { descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
if (descriptor.getDependencyType().equals(javaUtilOptionalClass)) {
// ObjectFactory 类注入的特殊处理
return new OptionalDependencyFactory().createOptionalDependency(descriptor, beanName);
}
else if (ObjectFactory.class == descriptor.getDependencyType()) {
// javaxInjectProviderClass 类注入的特殊处理
return new DependencyObjectFactory(descriptor, beanName);
}
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new DependencyProviderFactory().createDependencyProvider(descriptor, beanName);
}
else {
// 通用处理逻辑
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, beanName);
if (result == null) {
result = doResolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException { Class<?> type = descriptor.getDependencyType();
// 用于支持 Spring 中新增的注解 @Value
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(strVal, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
} // 如果解析器没有成功解析,则需要考虑各种情况
// 属性是数组类型
if (type.isArray()) {
Class<?> componentType = type.getComponentType();
// 根据属性类型找到 beanFactory 中所有类型的匹配 bean
// 返回值的构成为:key=匹配的 beanName, value=beanName 对应的实例化后的 bean(通过 getBean(beanName)返回)
DependencyDescriptor targetDesc = new DependencyDescriptor(descriptor);
targetDesc.increaseNestingLevel();
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType, targetDesc);
if (matchingBeans.isEmpty()) {
// 如果 autowire 的 require 属性为 true 而找到的匹配项却为空则只能抛出异常
if (descriptor.isRequired()) {
raiseNoSuchBeanDefinitionException(componentType, "array of " + componentType.getName(), descriptor);
}
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
// 通过转换器将 bean 的值转换为对应的 type 类型
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
Object result = converter.convertIfNecessary(matchingBeans.values(), type);
if (getDependencyComparator() != null && result instanceof Object[]) {
Arrays.sort((Object[]) result, adaptDependencyComparator(matchingBeans));
}
return result;
}
// 属性是 Collection 类型
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
Class<?> elementType = descriptor.getCollectionType();
if (elementType == null) {
if (descriptor.isRequired()) {
throw new FatalBeanException("No element type declared for collection [" + type.getName() + "]");
}
return null;
}
DependencyDescriptor targetDesc = new DependencyDescriptor(descriptor);
targetDesc.increaseNestingLevel();
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType, targetDesc);
if (matchingBeans.isEmpty()) {
if (descriptor.isRequired()) {
raiseNoSuchBeanDefinitionException(elementType, "collection of " + elementType.getName(), descriptor);
}
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
Object result = converter.convertIfNecessary(matchingBeans.values(), type);
if (getDependencyComparator() != null && result instanceof List) {
Collections.sort((List<?>) result, adaptDependencyComparator(matchingBeans));
}
return result;
}
// 属性是 Map 类型
else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
Class<?> keyType = descriptor.getMapKeyType();
if (String.class != keyType) {
if (descriptor.isRequired()) {
throw new FatalBeanException("Key type [" + keyType + "] of map [" + type.getName() +
"] must be [java.lang.String]");
}
return null;
}
Class<?> valueType = descriptor.getMapValueType();
if (valueType == null) {
if (descriptor.isRequired()) {
throw new FatalBeanException("No value type declared for map [" + type.getName() + "]");
}
return null;
}
DependencyDescriptor targetDesc = new DependencyDescriptor(descriptor);
targetDesc.increaseNestingLevel();
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, targetDesc);
if (matchingBeans.isEmpty()) {
if (descriptor.isRequired()) {
raiseNoSuchBeanDefinitionException(valueType, "map with value type " + valueType.getName(), descriptor);
}
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
return matchingBeans;
}
else {
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (descriptor.isRequired()) {
raiseNoSuchBeanDefinitionException(type, "", descriptor);
}
return null;
}
if (matchingBeans.size() > 1) {
String primaryBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (primaryBeanName == null) {
throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet());
}
if (autowiredBeanNames != null) {
autowiredBeanNames.add(primaryBeanName);
}
return matchingBeans.get(primaryBeanName);
}
// 已经可以确定只有一个匹配项
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
if (autowiredBeanNames != null) {
autowiredBeanNames.add(entry.getKey());
}
return entry.getValue();
}
}

寻找类型的匹配执行顺序时,首先尝试使用解析器进行解析,如果解析器没有成功解析,那么可能是使用默认的解析器没有做任何处理,或者是使用了自定义的解析器,但是对于集合等类型来说并不在解析范围之内,所以再次对不同类型进行不同情况的处理,虽说对于不同类型处理方式不一致,但是大致的思路还是很相似的,所以函数中只对数组类型进行了详细地注释。

3. applyPropertyValues

程序运行到这里,已经完成了对所有注入属性的获取,但是获取的属性是以 PropertyValues 形式存在的,还并没有应用到已经实例化的 bean 中,这一工作是在 applypropertyValues 中。

protected void applyPropertyValues(String beanName, BeanDefinition mbd,
BeanWrapper bw, PropertyValues pvs) {
if (pvs == null || pvs.isEmpty()) {
return;
} MutablePropertyValues mpvs = null;
List<PropertyValue> original; if (System.getSecurityManager() != null) {
if (bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
}
} if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
// 如果 mpvs 中的值已经被转换为对应的类型那么可以直接设置到 beanWarpper 中
if (mpvs.isConverted()) {
// Shortcut: use the pre-converted values as-is.
try {
bw.setPropertyValues(mpvs);
return;
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
original = mpvs.getPropertyValueList();
}
else {
// 如果 pvs 并不是使用 MutablePropertyValues 封装的类型,那么直接使用原始的属性获取方法
original = Arrays.asList(pvs.getPropertyValues());
} TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
} // 获取对应的解析器
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter); // Create a deep copy, resolving any references for values.
List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
boolean resolveNecessary = false;
// 遍历属性,将属性转换为对应类的对应属性的类型
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
String propertyName = pv.getName();
Object originalValue = pv.getValue();
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
boolean convertible = bw.isWritableProperty(propertyName) &&
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
if (convertible) {
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
// Possibly store converted value in merged bean definition,
// in order to avoid re-conversion for every created bean instance.
if (resolvedValue == originalValue) {
if (convertible) {
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
}
else if (convertible && originalValue instanceof TypedStringValue &&
!((TypedStringValue) originalValue).isDynamic() &&
!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
}
else {
resolveNecessary = true;
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
} // Set our (possibly massaged) deep copy.
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}

5.7.4 初始化 bean

大家应该记得在 bean 配置时 bean 中有一个 init-method 的属性,这个属性的作用是在 bean 实例化前调用 init-method 指定的方法来根据用户业务进行相应的实例化。我们现在就已经进入这个方法了,首先看一下这个方法的执行位置, Spring 中程序已经执行过 bean 的实例化,并且进行了属性的填充,而就在这日时将会调用用户设定的初始化方法。

protected Object initializeBean(final String beanName, final Object bean,
RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
// 对特殊的 bean 处理:Aware、BeanClassLoaderAware、BeanFactoryAware
invokeAwareMethods(beanName, bean);
} Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 应用后处理器
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
} try {
// 激活用户自定义的 init 方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
} if (mbd == null || !mbd.isSynthetic()) {
// 后处理器应用
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}

虽然说此函数的主要目的是进行客户设定的初始化方法的调用,但是除此之外还有些其他必要的工作。

1. 激活 Aware方法

在分析其原理之前,我们先了解一下 Aware 的使用。 Spring 中提供一些 Aware 相关接口,比如 BeanfactoryAware、 ApplicationContextAware、 ResourceLoaderAware、 ServletContextAware等,实现这些 Aware 接口的的 bean 在被初始之后,可以取得一些相对应的资源,例如实现 BeanfactoryAware 的 bean 在初始后, Spring 容器将会注入 BeanFactory 的实例,而实现 ApplicationContextAware 的 bean,在 bean 被初始后,将会被注人 ApplicationContext 的实例等。我们首先通过示例方法来了解一下 Aware 的使用。

按照上面的方法我们可以获取到 Spring 中 BeanFactory,并且可以根据 BeanFactory 获取所有 bean,以及进行相关设置。当然还有其他 Aware 的使用方法都大同小异,看一下 Spring 的实现方式,相信读者便会使用了。

private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}

代码简单得已经没有什么好说的了。读者可以自己尝试使用别的 Aware,都比较简单。

2.处理器的应用

BeanPostProcessor 相信大家都不陌生,这是 Spring 中开放式架构中一个必不可少的亮点,给用户充足的权限去更改或者扩展 Spring,而除了 BeanPostProcessor 外还有很多其他的 PostProcessor,当然大部分都是以此为基础,继承自 BeanPostProcessor。BeanPostProcessor 的使用位置就是这里,在调用客户自定义初始化方法前以及调用自定义初始化方法后分别会调用 BeanPostProcessor 的 postProcessBeforeInitialization 和 postProcessAfterInitialization 方法,使用用户可以根据自己的业务需求进行响应的处理。

public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean,
String beanName) throws BeansException { Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
} public Object applyBeanPostProcessorsAfterInitialization(Object existingBean,
String beanName) throws BeansException { Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessAfterInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}

3. 激活自定义的 int 方法

客户定制的初始化方法除了我们熟知的使用配置 init-method 外,还有使自定义的 bean 实现 InitializingBean 接口,并在 afterPropertiesSet 中实现自己的初始化业务逻辑。init-method 与 afterPropertiesSet 都是在初始化 bean 时执行,执行顺序是 afterPropertiesSet 先执行,而 init-method 后执行。在 invokeInitMethods 方法中就实现了这两个步骤的初始化方法调用。

protected void invokeInitMethods(String beanName, final Object bean,
RootBeanDefinition mbd) throws Throwable { // 首先会检查是否是 InitializingBean,如果是的话需要调用 afterPropertiesSet 方法
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
((InitializingBean) bean).afterPropertiesSet();
return null;
}
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
// 属性初始化后的处理
((InitializingBean) bean).afterPropertiesSet();
}
} if (mbd != null) {
String initMethodName = mbd.getInitMethodName();
if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
// 调用自定义初始化方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}

5.7.5 注册 DisposableBean

Spring 中不但提供了对于初始化方法的扩展入口,同样也提供了销毁方法的扩展入口,对于销毁方法的扩展,除了我们熟知的配置属性 destroy-method 方法外,用户还可以注册后处理器 DestructionAwareBeanPostProcessor 来统一处理 bean 的销毁方法,代码如下:

protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
if (mbd.isSingleton()) {
// 单例模式下注册需要销毁的 bean,此方法中会处理实现 DisposableBean 的 bean
// 并且对所有的 bean 使用 DestructionAwareBeanPostProcessors 处理
registerDisposableBean(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
else {
// 自定义 scope 处理
Scope scope = this.scopes.get(mbd.getScope());
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
}
scope.registerDestructionCallback(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
}
}

Spring 系列教程之 bean 的加载的相关教程结束。

《Spring 系列教程之 bean 的加载.doc》

下载本文的Word格式文档,以方便收藏与打印。