Spring 源码系列-依赖注入

Spring源码系列-BeanDefinition文章中大概分析了一下 Bean 的载入,其实这个过程就是在Ioc容器中建立BeanDefinition的数据映射。但是对于Bean的实例化并未涉及,在之前的分析中也提到,bean的实例化是在依赖注入是才具体完成。

关于依赖注入

关于Spring,我们最先想到的就两个Ioc和Aop;然后关于Ioc我们又能牵扯出两个:控制反转和依赖注入。
控制反转和依赖注入在网上被无数大神亦或菜鸟解读过,这里就不罗列那些概念了,直接看:

不使用Spring

1
2
3
4
5
6
7
public class UserService {
//手动new一个
UserDao userDao = new UserDaoImpl();
public int insertUser(String userName) {
return userDao.insertUser(userName);
}
}

使用Spring(以注解方式)

1
2
3
4
5
6
7
public class UserService {
@Autowired
private UserDao userDao;
public int insertUser(String userName) {
return userDao.insertUser(userName);
}
}

看起来貌似没有啥很大的改变,区别呢?

我们先来分析下在一个类中这两种申明的区别:

UserDao userDao;

userDao是UserDao类型的引用名称。仅仅是声明了一个变量引用名称。并没有做实例化,userDao的实例化可以通过set方法进行设置(Spring中之前常用的就是set方法注入);当我们初始化持有userDao的这个类时我们还不知道userDao到底具体指向哪个堆中的对象地址。

UserDao userDao = new UserDaoImpl();

而这个,申明一个变量名称,并将userDao直接指向new UserDaoImpl()创建的对象。

我们来看Spring中关于注入之后对象地址以及不使用注入方式对象的地址:

1、直接注入

2、注入覆盖了我自己的对象

3、自己手动new

通过上面三幅图可以明显的看出,自己手动new的对象没有使用代理的方式,而托管给Spring注入的对象均是通过动态代理来完成的。

关于动态代理:《猪弟拱Java》连载番外篇:Java代理(中)

总结:当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在未使用Spring来管理Bean的程序设计过程中,通常由调用者来创建被调用者的实例。但在Spring里,创建被调用者的工作不再由调用者来完成,因此称为控制反转;创建被调用者实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖注入。

三个问题

那么现在要考虑问题就是,什么时候会触发我们的依赖注入呢?Bean的实例化是否必须在依赖注入时才能完成呢?在Spring中又是通过哪些类来完成注入工作的呢?

1、什么时候会触发我们的依赖注入

答:用户第一次向容器获取Bean的时候出发。

2、Bean的实例化是否必须在依赖注入时才能完成

这个其实不是必须的,咱们都知道BeanDefinition中有lazy-init这样一个属性,我们可以通过控制这个属性的设置来让容器完成对Bean的预实例化。预实例化就是说它的依赖注入是在实例化过程中完成的。

第一和第二个问题将会在分析第三个问题的时候慢慢的细化分析。所以第三个问题其实没啥鸟用,但也是最最最核心的,就是为了引出后面关于一些具体类的分析的。

getBean

Spring源码系列:BeanFactory的创建文章中我们谈到了BeanFactory这容器,这个里面提供了注入的实现接口。其具体的实现还需要从AbstractBeanFactory和DefaultListableBeanFactory中来看。今天就先撸一下AbstractBeanFactory这个类中的getBean这个方法。

getBean

getBean提供了四个重载方法,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//通过name获取Bean
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
//通过name和类型获取Bean
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
//通过name和对象参数获取Bean
@Override
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, null, args, false);
}
//通过name、类型和参数获取Bean
public <T> T getBean(String name, Class<T> requiredType, Object... args) throws BeansException {
return doGetBean(name, requiredType, args, false);
}

从这四个重载方法的方法体中可以看出,他们都是通过doGetBean来实现的。所以doGetBean其实才是真正获取Bean的地方,也是触发依赖注入发生的地方。(这个方法比较长,分段来说)

doGetBean

先来看下方法的定义:

1
2
3
4
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
  • name 要检索的bean的名称
  • requiredType 要检索的bean所需的类型
  • args 使用显式参数创建bean实例时使用的参数(仅在创建新实例时应用,而不是在检索现有实例时应用)
  • typeCheckOnly 是否为类型检查而获得实例,而不是实际使用
1
2
3
4
5
6
7
8
//返回bean名称,剥离工厂引用前缀,并将别名解析为规范名称。
final String beanName = transformedBeanName(name);
//声明当前需要返回的bean对象
Object bean;

// 先从缓存中获取bean,处理已经被创建的单例模式的bean,
//对于此类bean的请求不需要重复的创建(singleton)
Object sharedInstance = getSingleton(beanName);

如果当前获取到的sharedInstance不为null并且参数为空,则进行FactoryBean的相关处理,并获取FactoryBean的处理结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
//返回指定的singleton bean是否正在创建(在整个工厂内)。
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 + "'");
}
}
//完成FactoryBean的相关处理,并用来获取FactoryBean的处理结果
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}

如果当前获取到的sharedInstance为null,我们再来看下做了哪些处理(下面的都在一个大的else里面):

1
2
3
else {
//分解到下面
}
1
2
3
4
//在当前线程中,返回指定的prototype bean是否正在创建。
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}

下面这段的作用是对Ioc容器中的BeanDefinition是否存在进行检测,先是检测当前BeanFactory中是否能够获取到,如果取不到则继续到双亲容器中进行尝试获取,如果双亲还是取不到,则继续向上一级父容器中尝试获取。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 检查该工厂是否存在bean定义。
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 如果没有,则继续检查父类
String nameToLookup = originalBeanName(name);
if (args != null) {
// 用明确的参数代表父项。
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// 如果没有args - >委托给标准的getBean方法。
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}

将指定的bean标记为已经创建(或即将创建);这里允许bean工厂优化其缓存以重复创建指定的bean。

1
2
3
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}

先根据beanName来获取BeanDefinition,然后获取当前bean的所有依赖bean,这里是通过递归调用getBean来完成,直到没有任何依赖的bean为止。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//检查给定的合并bean定义,可能抛出验证异常。
checkMergedBeanDefinition(mbd, beanName, args);
// 保证当前bean依赖的bean的初始化。
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
//递归处理依赖bean
getBean(dep);
}
}

下面这段就是创建一个bean实例;这里通过调用getSingleton方法来创建一个单例bean实例;从代码中可以看到,getSingleton的调用是通过getObject这个回调函数来间接调用createBean完成的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
//回调函数getObject
@Override
public Object getObject() throws BeansException {
try {
//创建bean
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
//发生异常则销毁
destroySingleton(beanName);
throw ex;
}
}
});
//获取给定bean实例的对象,无论是bean实例本身,还是FactoryBean创建的对象。
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

下面是创建prototype bean

1
2
3
4
5
6
7
8
9
10
11
12
else if (mbd.isPrototype()) {
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
//创建prototype bean
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

最后是对创建的bean进行类型检查,没有问题就返回已经创建好的bean;此时这个bean是包含依赖关系的bean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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());
}
}
//返回bean
return (T) bean;

getBean是依赖注入的起点,从上面的分析可以看出,bean的创建都是通过createBean来完成具体的创建的。createBean的具体实现是在AbstractAutowireCapableBeanFactory中的,这里createBean不仅仅负责创建bean,还需要完成对bean的初始化。

createBean

getBean 是依赖注入的起点,bean 的创建都是通过 createBean 来完成具体的创建的。createBean 的具体实现是在AbstractAutowireCapableBeanFactory 中的。

这个方法是 AbstractAutowireCapableBeanFactory 这个类的中心方法,其作用就是创建一个bean实例,填充bean实例,后置处理等。

在createBean中主要做了三件事:

  • 判断需要创建的Bean是否可以实例化,这个类是否可以通过类装载器来载入
  • 是否配置了后置处理器相关处理(如果配置了则返回一个代理)
  • 创建Bean

具体来看方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
//判断需要创建的Bean是否可以实例化,这个类是否可以通过类装载器来载入
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}

// Prepare method overrides.
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
//异常:Validation of method overrides failed
}

try {
// Give BeanPostProcessors a chance to return a proxy instead of the target
//bean instance.
//是否配置了后置处理器相关处理(如果配置了则返回一个代理)
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
//异常:BeanPostProcessor before instantiation of bean failed
}
//创建Bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}

从上面的代码中可以看到,创建bean是交给doCreateBean方法来创建的。继续看doCreateBean这个方法:
(这里面涉及到一个BeanWrapper这个接口,小伙伴可以移步了解一下《Spring源码系列:BeanWrapper》)

代码 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 用BeanWrapper来持有创建出来的Bean对象
BeanWrapper instanceWrapper = null;
//如果是单例的话,则先把缓存中的同名bean清除
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
//实际创建的交给createBeanInstance来完成,
//bean的生成,这里会使用默认的类生成器,包装成BeanWrapperImpl类,
//为了下面的populateBean方法的属性注入做准备
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
mbd.resolvedTargetType = beanType;

代码 2:

允许后处理器修改合并的bean定义。

1
2
3
4
5
6
7
8
9
10
11
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
//异常:Post-processing of merged bean definition failed
}
mbd.postProcessed = true;
}
}

代码 3 :

即使被BeanFactoryAware等生命周期接口触发,也要尽快地缓存singletons 以便能够解析循环引用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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");
}
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}

代码 4:

这里是对bean的初始化的地方,一般情况下依赖注入就在这里发生;这个exposedObject变量保存的是在初始化处理完以后返回的作为依赖注入完成之后的bean。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
catch (Throwable ex) {
//抛出
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException)
ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
//异常:Initialization of bean failed
}
}

代码 5:

这里是注册bean

1
2
3
4
5
6
7
8
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
//异常处理
}
//返回结果
return exposedObject;

上面的5个代码段均是doCreateBean中的处理逻辑,有兴趣的小伙伴可以自行查阅源码。从上面的代码中我们依然没有得到具体创建的过程,因为在doCreateBean中又依赖:createBeanInstancepopulateBean两个方法。

createBeanInstance中生成了Bean所包含的java对象。来看是怎么生成的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// 确保bean类实际上已经解析过了,可以实例化
Class<?> beanClass = resolveBeanClass(mbd, beanName);

if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
//异常:Bean class isn't public, and non-public access not allowed:beanName
}
//1. 使用工厂方法来进行bean的实例化
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}

// 重新创建相同的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);
}
}

// 2.需要确定构造函数...,使用构造函数进行bean实例化
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}

//3.没有特殊的处理:只需使用无参数构造函数。(默认构造函数)
return instantiateBean(beanName, mbd);
}

从上面这段代码可以看出,对象的生成有许多不同的方式,有通过工厂的,也有通过容器的autowire特性生成的。当然这些生成方式都是由相关的BeanDefinition来指定的。

Spring中配置Bean的方式我们常用的一种是通过xml文件来配置,还有就是通过注解的方式来配置

  • demo1
1
2
3
<bean id="user" class="com.glmapper.test.User">
<property name="name" value="glmapper"></property>
</bean>

这种方式,通过class提供的权限定名,spring就可以利用反射机制创建这个bean。

  • demo2
1
2
3
<bean id="user" class="com.glmapper.test.UserFactory" factory-method="getUser">
<constructor-arg value="glmapper"></constructor-arg>
</bean>

这种是利用静态工厂方法来创建的,提供的class并非是类的权限定名, 而是静态工厂的全类名;除此之外还需要指定获取bean的方法(此处是getUser)和参数(参数是glmapper)。

  • demo3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<bean id="userFactory" class="com.glmapper.test.UserInstanceFactory">
<!--用一个集合来保存我当前的对象实例-->
<property name="map">
<map>
<entry key="user1">
<bean class="com.glmapper.test.User">
<property name="name" value="glmapper1"></property>
</bean>
</entry>

<entry key="user2">
<bean class="com.glmapper.test.User">
<property name="name" value="glmapper2"></property>
</bean>
</entry>
</map>
</property>
</bean>

//实例1
<bean id="user1" factory-bean="userFactory" factory-method="getUserInstance">
<constructor-arg value="user1"></constructor-arg>
</bean>
//实例2
<bean id="user2" factory-bean="userFactory" factory-method="getUserInstance">
<constructor-arg value="user2"></constructor-arg>
</bean

这种方式和静态工厂的区别在于我们需要先实例化一个工厂对象,然后才能使用这个工厂对象来创建我们的bean。getUserInstance通过key值来获取我们已经实例化好的对象(当然方式有很多,此处以map来举个例子)。关于注解的和使用FactoryBean接口的这里就暂时不说,后期再聊

OK,继续来分钟,上面说到的是以工厂方法创建bean,具体的源码有点长,这里就不放了,大概思路就如上面所提到的那几种方式。接下来看下常见的使用instantiateBean方式(使用它的默认构造函数)来构建bean的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
//获取系统安全接口。
//如果已经为当前应用程序建立了安全管理器,则返回该安全管理器;
//否则,返回null。
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) {
//异常:Instantiation of bean failed
}
}

可以看出,上面的创建都是通过:

1
getInstantiationStrategy().instantiate(mbd, beanName, parent);

这样一段代码来完成的,是的,这里已经快接近真相了。从语义上来分析,先是获取了一种策略,然后利用当前获取的策略再去执行实例化。OK,我们看下getInstantiationStrategy()拿到的是什么:

1
2
3
4
5
6
//返回实例化策略用于创建bean实例。
protected InstantiationStrategy getInstantiationStrategy() {
return this.instantiationStrategy;
}
//默认的实例化测试是使用CGLIB代理
private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

看到这里我们清楚了,默认构造函数的情况下,在spring中会使用Cglib来进行bean的实例化(关于cglib此处不再赘述)。我们看下CglibSubclassingInstantiationStrategy这个类的申明:

1
public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationStrategy 

它继承自SimpleInstantiationStrategy ,这个又是什么鬼呢?

SimpleInstantiationStrategy是Spring用来生成Bean对象的默认类,在这个类中提供了两种实例化java对象的方法,一种是基于java自身反射机制的BeanUtils,还有一种就是基于Cglib

如何创建的就不说了;到这里createBeanInstance就说完了(Bean已经创建了);但是仅仅是创建,spring还没有处理它们,比如说bean对象的属性,依赖关系等等。这些就是上面提到的另外一个方法populateBean;

这个方法其实就做了一件事:使用bean定义中的属性值在给定的BeanWrapper中填充bean实例。分段来看:
下面这段代码是先将BeanDefinition中设置的property值封装成PropertyValues,然后检测我们的BeanWrapper是否为Null,如果为null则抛出异常或者跳过当前空实例赋值阶段

1
2
3
4
5
6
7
8
9
10
11
//获取到BeanDefinition中设置的property值,封装成PropertyValues
PropertyValues pvs = mbd.getPropertyValues();
if (bw == null) {
if (!pvs.isEmpty()) {
//异常:Cannot apply property values to null instance
}
else {
// Skip property population phase for null instance.
return;
}
}

下面这段代码的意思是给任何InstantiationAwareBeanPostProcessors提供在设置属性之前修改bean状态的机会。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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;
}

下面就是对具体注入方式的处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//处理autowire的注入;可以根据bean的名称和类型来注入
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;
}

两个判断条件,在满足的情况下做的处理分别是:

  • 在工厂将给定属性值应用到给定的bean后,对其进行后处理。 允许检查所有的依赖关系是否被满足,例如基于bean属性设置器上的“Required”注解。还允许替换要应用的属性值,通常通过创建基于原始PropertyValues的新MutablePropertyValues实例,添加或删除特定值。
  • 执行依赖性检查
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//返回这个工厂是否拥有一个InstantiationAwareBeanPostProcessor
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
//返回依赖检查代码。
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

if (hasInstAwareBpps || needsDepCheck) {
//从给定的BeanWrapper中提取一组已过滤的PropertyDescriptors,
//不包括在被忽略的依赖性接口上定义的被忽略的依赖类型或属性(译注)。
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) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}

最后是对属性进行注入:

1
applyPropertyValues(beanName, mbd, bw, pvs);

这个方法描述的是对属性进行解析然后注入的过程;先来分析下applyPropertyValues的申明:

1
2
protected void applyPropertyValues(String beanName
, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs)
  • beanName bean名称
  • mbd 合并的bean definition
  • bw 包装目标对象的BeanWrapper
  • pvs 新的属性值

代码分段来看:

  • 参数验证

    1
    2
    3
    if (pvs == null || pvs.isEmpty()) {
    return;
    }
  • pvs参数处理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    if (pvs instanceof MutablePropertyValues) {
    mpvs = (MutablePropertyValues) pvs;
    if (mpvs.isConverted()) {
    // 使用预先转换后的值。
    try {
    bw.setPropertyValues(mpvs);
    return;
    }
    catch (BeansException ex) {
    //异常:Error setting property values
    }
    }
    original = mpvs.getPropertyValueList();
    }
    else {
    original = Arrays.asList(pvs.getPropertyValues());
    }
  • valueResolver来解析BeanDefinition

    1
    2
    BeanDefinitionValueResolver valueResolver = 
    new BeanDefinitionValueResolver(this, beanName, mbd, converter);
  • 为解析值创建一个副本,注入到bean中的是副本的数据

    1
    2
    // Create a deep copy, resolving any references for values.
    List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
  • 遍历处理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    boolean resolveNecessary = false;
    for (PropertyValue pv : original) {
    //返回此持有者是否已经包含转换后的值(true),还是需要转换值(false)。
    if (pv.isConverted()) {
    deepCopy.add(pv);
    }
    else {
    String propertyName = pv.getName();
    Object originalValue = pv.getValue();
    //看下面的注释resolveValueIfNecessary
    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);
    }
    // 可能将转换的值存储在合并的bean定义中,以避免为每个创建的bean实例重新转换。
    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));
    }
    }
    }

    resolveValueIfNecessary 给定一个PropertyValue,返回一个value,必要时解析对工厂中其他bean的引用。value可以是:

  • 一个BeanDefinition,它导致创建一个相应的新的bean实例。 Singleton标志和这样的”inner beans”的名字被忽略:内部beans是匿名原型。

  • RuntimeBeanReference(必须解析)

  • ManagedList

  • ManagedSet

  • ManagedMap

  • 一个普通的对象或null,在这种情况下,它是孤立的。

下面这段代码时依赖注入发生的地方,其实际上是在BeanWrapperImpl中来完成。

1
2
3
4
5
6
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
//异常:Error setting property values
}

上面说到 spring 是通过 BeanDefinitionValueResolver 来解析 BeanDefinition 的,然后再注入到 property 中,关于这个过程见下一小节。

属性注入

前面文章中对依赖注入的触发和bean的创建做了学习记录,本文将来记录一下bean的属性注入过程。Bean的属性注入发生在BeanDefinitionValueResolver这个类中,BeanDefinitionValueResolver这类是用于bean工厂实现的Helper类,职责就是将bean定义对象中包含的值解析为应用于目标bean实例的实际值。

BeanDefinitionValueResolver类中的resolveValueIfNecessary()方法包含了对所有注入类型的处理。所以本文主要围绕这个方法展开来说。

resolveValueIfNecessary方法

resolveValueIfNecessary():给定一个PropertyValue,返回一个value,解析对工厂中其他bean的引用。 value可能是:

  • RuntimeBeanReference : 在解析到依赖的Bean的时侯,解析器会依据依赖bean的name创建一个RuntimeBeanReference对像,将这个对像放入BeanDefinition的MutablePropertyValues中。
  • ManagedList:用来保存它所管理的List元素,它可以包含运行时期的bean引用(将被解析为bean对象).
  • ManagedSet :用来保存它所管理的set值,它可以包含运行时期的bean引用(将被解析为bean对象)
  • ManagedMap :用来保存它所管理的map值,它可以包含运行时期的bean引用(将被解析为bean对象)

1、方法申明

argName :为其定义的参数的名称

value :要解析的值对象

1
public Object resolveValueIfNecessary(Object argName, Object value)

2、RuntimeBeanReference

当在beanfactory中作为另外一个bean的引用时,作为属性值对象,将在运行时进行解析。 RuntimeBeanReference是在对BeanDefinition进行解析时生成的数据对象。

1
2
3
4
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
return resolveReference(argName, ref);
}

3、RuntimeBeanNameReference

当在beanfactory中作为另外一个bean名称的引用时,作为属性值对象,将在运行时进行解析。

1
2
3
4
5
6
7
8
else if (value instanceof RuntimeBeanNameReference) {
String refName = ((RuntimeBeanNameReference) value).getBeanName();
refName = String.valueOf(doEvaluate(refName));
if (!this.beanFactory.containsBean(refName)) {
//异常:Invalid bean name '" + refName + "' in bean reference for " + argName
}
return refName;
}

4、BeanDefinitionHolder

解析BeanDefinitionHolder:包含具有名称和别名的BeanDefinition。BeanDefinitionHolder就是使用名称或者别名来保存BeanDefinition的。

1
2
3
4
else if (value instanceof BeanDefinitionHolder) {
BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
}

5、BeanDefinition

解析纯粹的BeanDefinition

1
2
3
4
5
6
7
else if (value instanceof BeanDefinition) {
// Resolve plain BeanDefinition, without contained name: use dummy name.
BeanDefinition bd = (BeanDefinition) value;
String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +
ObjectUtils.getIdentityHexString(bd);
return resolveInnerBean(argName, innerBeanName, bd);
}

6、ManagedArray

包含运行时期的bean引用(将被解析为bean对象)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
else if (value instanceof ManagedArray) {
// May need to resolve contained runtime references.
ManagedArray array = (ManagedArray) value;
Class<?> elementType = array.resolvedElementType;
if (elementType == null) {
String elementTypeName = array.getElementTypeName();
if (StringUtils.hasText(elementTypeName)) {
try {
elementType = ClassUtils.forName(elementTypeName,
this.beanFactory.getBeanClassLoader());
array.resolvedElementType = elementType;
}
catch (Throwable ex) {
// Improve the message by showing the context.
//异常:Error resolving array type for " + argName
}
}
else {
elementType = Object.class;
}
}
return resolveManagedArray(argName, (List<?>) value, elementType);
}

7、ManagedList,ManagedSet,ManagedMap

包含运行时期的bean引用(将被解析为bean对象)

1
2
3
4
5
6
7
8
9
10
11
12
//对ManagedList进行解析
else if (value instanceof ManagedList) {
return resolveManagedList(argName, (List<?>) value);
}
//对ManagedSet进行解析
else if (value instanceof ManagedSet) {
return resolveManagedSet(argName, (Set<?>) value);
}
//对ManagedMap进行解析
else if (value instanceof ManagedMap) {
return resolveManagedMap(argName, (Map<?, ?>) value);
}

8、ManagedProperties

ManagedProperties表示的是一个spring管理的属性实例,它支持父/子 definition的合并。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//对ManagedProperties进行解析
else if (value instanceof ManagedProperties) {
Properties original = (Properties) value;
Properties copy = new Properties();
for (Map.Entry<Object, Object> propEntry : original.entrySet()) {
Object propKey = propEntry.getKey();
Object propValue = propEntry.getValue();
if (propKey instanceof TypedStringValue) {
propKey = evaluate((TypedStringValue) propKey);
}
if (propValue instanceof TypedStringValue) {
propValue = evaluate((TypedStringValue) propValue);
}
copy.put(propKey, propValue);
}
return copy;
}

9、TypedStringValue

TypedStringValue保存的是一个类型的属性值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//对TypedStringValue进行解析
else if (value instanceof TypedStringValue) {
// Convert value to target type here.
TypedStringValue typedStringValue = (TypedStringValue) value;
Object valueObject = evaluate(typedStringValue);
try {
Class<?> resolvedTargetType = resolveTargetType(typedStringValue);
if (resolvedTargetType != null) {
return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType);
}
else {
return valueObject;
}
}
catch (Throwable ex) {
// Improve the message by showing the context.
throw new BeanCreationException(
//异常:Error converting typed String value for " + argName
}
}

10、作为表达式进行评估

将给定的值作为表达式进行评估。

1
2
3
else {
return evaluate(value);
}

在完成上述解析之后,已经为我们的依赖注入做好了准备。这是真正把Bean对象设置到它所依赖的另一个Bean的属性中去的地方,可以看到,处理的属性也是各式各样的。具体属性的注入是在之前提到的BeanWrapper接口的实现类BeanWrapperImpl的setPropertyValue方法来完成。

setPropertyValue方法

a、方法声明

这个方法是私有的,是BeanWrapperImpl实际处理的方法,其对外也提供了setPropertyValue的其它重载方法来提供服务。

1
2
private void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv)
throws BeansException

b、PropertyTokenHolder是BeanWrapperImpl的内部类

1
2
3
4
5
private static class PropertyTokenHolder {
public String canonicalName;
public String actualName;
public String[] keys;
}

在setPropertyValue方法中会根据tokens变量是否为null,有两个不同的分支。其中当tokens为null时,则会对属性名进行递归调用分析处理,返回分析处理后的BeanWrapImpl对象nestedBw。如果nestedBw==this,则会设置pv的resolvedTokens属性值,最后将调用nestedBw对象的设置属性值方法设置属性。来具体看看:

c、其中当tokens为null时,即对集合类的域进行注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 设置tokens的索引和keys
PropertyTokenHolder getterTokens = new PropertyTokenHolder();
getterTokens.canonicalName = tokens.canonicalName;
getterTokens.actualName = tokens.actualName;
getterTokens.keys = new String[tokens.keys.length - 1];
System.arraycopy(tokens.keys, 0, getterTokens.keys, 0, tokens.keys.length - 1);
Object propValue;
//getPropertyValue用来获取Bean中对对象注入的引用;
try {
propValue = getPropertyValue(getterTokens);
}
catch (NotReadablePropertyException ex) {
//异常:Cannot access indexed value in property referenced
}

1、propValue为null

propValue为null

1
2
3
4
5
6
7
8
9
10
11
12
13
if (propValue == null) {
// 空值映射的情况
if (this.autoGrowNestedPaths) {
// TODO: cleanup, this is pretty hacky
int lastKeyIndex = tokens.canonicalName.lastIndexOf('[');
getterTokens.canonicalName = tokens.canonicalName.substring(0, lastKeyIndex);
propValue = setDefaultValue(getterTokens);
}
else {
//异常:Cannot access indexed value in property referenced " +
"in indexed property path '" + propertyName + "': returned null"
}
}

2、对array进行注入

对array进行注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if (propValue.getClass().isArray()) {
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
Class requiredType = propValue.getClass().getComponentType();
int arrayIndex = Integer.parseInt(key);
Object oldValue = null;
try {
if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
oldValue = Array.get(propValue, arrayIndex);
}
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
requiredType, TypeDescriptor.nested(property(pd), tokens.keys.length));
Array.set(propValue, arrayIndex, convertedValue);
}
catch (IndexOutOfBoundsException ex) {
//异常:Invalid array index in property path '" + propertyName
}
}

2、对list进行注入

对list进行注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
else if (propValue instanceof List) {
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
Class requiredType = GenericCollectionTypeResolver.getCollectionReturnType(
pd.getReadMethod(), tokens.keys.length);
List list = (List) propValue;
int index = Integer.parseInt(key);
Object oldValue = null;
if (isExtractOldValueForEditor() && index < list.size()) {
oldValue = list.get(index);
}
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
requiredType, TypeDescriptor.nested(property(pd), tokens.keys.length));
int size = list.size();
if (index >= size && index < this.autoGrowCollectionLimit) {
for (int i = size; i < index; i++) {
try {
list.add(null);
}
catch (NullPointerException ex) {
//异常:InvalidPropertyException
}
}
list.add(convertedValue);
}
else {
try {
list.set(index, convertedValue);
}
catch (IndexOutOfBoundsException ex) {
//异常:Invalid list index in property path '" + propertyName + "'"
}
}
}

2、对map进行注入

对map进行注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
else if (propValue instanceof Map) {
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
Class mapKeyType = GenericCollectionTypeResolver.getMapKeyReturnType(
pd.getReadMethod(), tokens.keys.length);
Class mapValueType = GenericCollectionTypeResolver.getMapValueReturnType(
pd.getReadMethod(), tokens.keys.length);
Map map = (Map) propValue;
//重要提示:不要在这里传递完整的属性名称
TypeDescriptor typeDescriptor = (mapKeyType != null ?
TypeDescriptor.valueOf(mapKeyType) : TypeDescriptor.valueOf(Object.class));
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, typeDescriptor);
Object oldValue = null;
if (isExtractOldValueForEditor()) {
oldValue = map.get(convertedMapKey);
}
// 在这里传递完整的属性名称和旧值,因为希望对map值有完整的转换能力。
Object convertedMapValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
mapValueType, TypeDescriptor.nested(property(pd), tokens.keys.length));
map.put(convertedMapKey, convertedMapValue);
}

其中当tokens不为null时,即对非集合类的域进行注入

这里是核心的地方,取得注入属性的set方法,通过反射机制,把对象注入进去。

1
2
3
final Method writeMethod = (pd instanceof GenericTypeAwarePropertyDescriptor ?
((GenericTypeAwarePropertyDescriptor) pd).getWriteMethodForActualAccess() :
pd.getWriteMethod());

总结

通过上面的几篇分析我们大概的熟悉了Bean创建和对象依赖注入的一个过程,在这个过程中,spring需要根据Beandefinition中的信息来递归完成依赖注入。并且这些递归的入口都是getBean这个方法。

一个递归是在上下文体系中查找需要的Bean和创建Bean的递归调用;

另一个递归是在依赖注入时通过递归调用容器的getBean方法,得到当前Bean的依赖Bean,同时也触发对依赖Bean的创建和注入。

在对Bean的属性进行依赖注入时解析的过程也是一个递归的过程。这样就可以根据依赖关系,一层一层的完成Bean的创建和注入,直到最后完成当前Bean的创建。

总结

依赖注入调用过程

如前几篇文章所述,依赖注入是由 getBean 来触发的;然后涉及到 bean 实例的创建、依赖关系的建立、属性注入等子过程。

  • getBean 方法触发依赖注入
  • doGetBean 从容器中查找Bean(BeanFactory链,当前容器->双亲容器-双亲容器…)

当然,在获取到某个Bean的时候也会通过递归的方式来依赖注入依赖的bean

  • createBeanInstance 生成了Bean所包含的Java对象,Spring中用SimpleInstantiationStrategy类来生成Bean对象的实例,实例化Java对象的方法有两种(CGlib是默认方式):

    • 通过BeanUtils,它使用了JVM的反射功能来生成Java对象实例
    • 用CGLIB来生成,CGLIB是一种常用的字节码生成器的类库
  • populateBean 设置Bean对象的依赖关系

  • resolveValueIfNecessary 注入类型的处理;解析不同类型的属性

  • setPropertyValues 属性注入

关于lazy-init

Ioc 容器的初始化过程中,主要的工作就是对BeanDefinition的定位、载入、解析和注册;但是就像之前说过的,此时依赖注入还没有发生。在getBean 方法提到,依赖注入发生在应用第一次向容器获取 Bean 的时候;也就是上面说到的通过 getBean 来触发。

当然,依赖注入也可以在容器初始化的过程中就完成。这个就是lazy-init属性的存在意义了。就是说我们可以通过设置Bean的lazy-init属性来控制预实例化的过程。

预实例化:在初始化容器时完成Bean的依赖注入

这种做法的好处在于提高了我们第一次获取Bean的的效率,但是它也降低了容器初始化的速度。(这个其实很好理解的,因为第一次获取Bean的时候,依赖注入已经完成了,直接拿过来用就行)

关于lazy-init属性的处理也是在wac.refresh这个方法中完成的,具体是在finishBeanFactoryInitialization方法中。如果继续追溯的话,最终是交给DefaultListableBeanFactory容器中的preInstantiateSingletons方法中完成。

lazy-init这种实例化方式就是通过将依赖注入委托给容器来处理,而不是在用户第一向容器申请的Bean的时候完成依赖注入,不同的阶段,也有不同的优劣。

参考

作者

卫恒

发布于

2018-02-07

更新于

2022-04-24

许可协议

评论