疯狂的小鸡

DI的实现

字数统计: 2k阅读时长: 9 min
2018/10/01 Share

本文章着重分析DI发生时的方法链调用。阅读本文章时,强烈建议打开IDE自己跟着方法调用一层层走。建议从BeanFactory类中的getBean()方法入手。

IoC容器的初始化过程仅仅是建立了BeanDefinition的数据映射。但Bean的依赖关系尚未建立。 依赖注入的触发时机有可以分为两类。对于懒加载的对象,依赖注入发生在用户第一次调用getBean()向容器索要bean时。对于非懒加载对象则是发生在容器初始化时。

doGetBean()

我们先从第一类谈起。getBean()方法是依赖注入发生的地方,他的实现从AbstractBeanFactory类看起。可以看到,实际获取bean调用doGetBean()方法。
在doGetBean()方法的try代码块中可以发现,方法递归调用getBean()来获取bean的所有依赖。实际获取bean的代码是try下面的createBean()方法中的doCreateBean()方法。doCreateBean()中有两个值得注意的方法,一个是createBeanInstance, 一个是populateBean。其中createBeanInstance方法生成了bean中所包含的Java对象,而populateBean则负责设置这些对象的属性处理。

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
//doGetBean()局部代码
final RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
this.checkMergedBeanDefinition(mbd, beanName, args);
String[] dependsOn = mbd.getDependsOn();
String[] var11;
if (dependsOn != null) {
var11 = dependsOn;
int var12 = dependsOn.length;

for(int var13 = 0; var13 < var12; ++var13) {
String dependsOnBean = var11[var13];
if (this.isDependent(beanName, dependsOnBean)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'");
}

this.registerDependentBean(dependsOnBean, beanName);
this.getBean(dependsOnBean);
}
}

if (mbd.isSingleton()) {
sharedInstance = this.getSingleton(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
try {
return AbstractBeanFactory.this.createBean(beanName, mbd, args);
} catch (BeansException var2) {
AbstractBeanFactory.this.destroySingleton(beanName);
throw var2;
}
}
});

createBeanInstance()

先看createBeanInstance方法。 该方法内提供了3种生产bean的方法,第一是通过工厂方法,第二是通过带参构造函数,第三是通过默认无参构造函数。其中第三种是最常用的实例化过程。实例化策略一是通过BeanUtils, 它使用了JVM反射功能,策略二是通过cglib,默认策略是使用cglib。具体实例化过程就不进行描述了。

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 createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
Class<?> beanClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
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());
} else if (mbd.getFactoryMethodName() != null) {
return this.instantiateUsingFactoryMethod(beanName, mbd, args);
} else {
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
Object var7 = mbd.constructorArgumentLock;
synchronized(mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
return autowireNecessary ? this.autowireConstructor(beanName, mbd, (Constructor[])null, (Object[])null) : this.instantiateBean(beanName, mbd);
} else {
Constructor<?>[] ctors = this.determineConstructorsFromBeanPostProcessors(beanClass, beanName);
return ctors == null && mbd.getResolvedAutowireMode() != 3 && !mbd.hasConstructorArgumentValues() && ObjectUtils.isEmpty(args) ? this.instantiateBean(beanName, mbd) : this.autowireConstructor(beanName, mbd, ctors, args);
}
}
}

populateBean()

我们的关注的重点是spring如何设置实例化bean的属性的,具体实现在populateBean方法中寻找。可以看到,在判断确认continueWithPropertyPopulation后,spring首先进行autowired自动装配,可根据bean的名字或者类型装配。反应到开发代码上,@Autowired注解就是默认按类型装配,而@Resource注解默认按名字装配。

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
44
45
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues();
//部分判断代码省略
if (continueWithPropertyPopulation) {
if (mbd.getResolvedAutowireMode() == 1 || mbd.getResolvedAutowireMode() == 2) {
MutablePropertyValues newPvs = new MutablePropertyValues((PropertyValues)pvs);
if (mbd.getResolvedAutowireMode() == 1) {
this.autowireByName(beanName, mbd, bw, newPvs);
}

if (mbd.getResolvedAutowireMode() == 2) {
this.autowireByType(beanName, mbd, bw, newPvs);
}

pvs = newPvs;
}

boolean hasInstAwareBpps = this.hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = mbd.getDependencyCheck() != 0;
if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = this.filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
Iterator var9 = this.getBeanPostProcessors().iterator();

while(var9.hasNext()) {
BeanPostProcessor bp = (BeanPostProcessor)var9.next();
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;
pvs = ibp.postProcessPropertyValues((PropertyValues)pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}

if (needsDepCheck) {
this.checkDependencies(beanName, mbd, filteredPds, (PropertyValues)pvs);
}
}

this.applyPropertyValues(beanName, mbd, bw, (PropertyValues)pvs);
}
}
}

Autowired的实现较简单,以autowiredByName为例,首先它要知道当前bean的属性名,而属性名已经在BeanDefinition中封装好了,可以直接获取。在匹配过程中,由于又了属性名字,可以直接向容器索取,触发当前依赖bean的依赖注入,从而得到该依赖bean。代码就不贴了。

applyPropertyValues()

若无法进行自动装配,则调用applyPropertyValues方法对属性进行解析然后注入。该方法首先为解析值创建了一个副本,在方法最后会调用setPropertyValues方法将副本数据注入到bean中。中间使用一个循环将解析值存到副本中。这里通过BeanDefinitionValueResolver中的resolveValueIfNecessary方法来对BeanDefinition进行解析。

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if (pvs != null && !pvs.isEmpty()) {
MutablePropertyValues mpvs = null;
if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl)bw).setSecurityContext(this.getAccessControlContext());
}

List original;
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues)pvs;
if (mpvs.isConverted()) {
try {
bw.setPropertyValues(mpvs);
return;
} catch (BeansException var18) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", var18);
}
}

original = mpvs.getPropertyValueList();
} else {
original = Arrays.asList(pvs.getPropertyValues());
}

TypeConverter converter = this.getCustomTypeConverter();
if (converter == null) {
converter = bw;
}

BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, (TypeConverter)converter);
List<PropertyValue> deepCopy = new ArrayList(original.size());
boolean resolveNecessary = false;
Iterator var11 = original.iterator();

while(true) {
while(var11.hasNext()) {
PropertyValue pv = (PropertyValue)var11.next();
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 = this.convertForProperty(resolvedValue, propertyName, bw, (TypeConverter)converter);
}

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();
}

try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
return;
} catch (BeansException var19) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", var19);
}
}
}
}

resolveValueIfNecessary()

通过resolveValueIfNecessary方法我们可以看到,该方法中通过if-else完成了对所有注入类型的处理。resolveValueIfNecessary方法完成了对所有注入类型的处理,但真正的注入发生在setPropertyValues方法中。观察该方法可以看到该方法同样通过判断对完成了对所有注入类型进行了处理。两者代码结构几乎一样,这里就不贴setPropertyValues代码了。

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
public Object resolveValueIfNecessary(Object argName, Object value) {
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference)value;
return this.resolveReference(argName, ref);
} else if (value instanceof RuntimeBeanNameReference) {
String refName = ((RuntimeBeanNameReference)value).getBeanName();
refName = String.valueOf(this.doEvaluate(refName));
if (!this.beanFactory.containsBean(refName)) {
throw new BeanDefinitionStoreException("Invalid bean name '" + refName + "' in bean reference for " + argName);
} else {
return refName;
}
} else if (value instanceof BeanDefinitionHolder) {
BeanDefinitionHolder bdHolder = (BeanDefinitionHolder)value;
return this.resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
} else if (value instanceof BeanDefinition) {
BeanDefinition bd = (BeanDefinition)value;
String innerBeanName = "(inner bean)#" + ObjectUtils.getIdentityHexString(bd);
return this.resolveInnerBean(argName, innerBeanName, bd);
} else if (value instanceof ManagedArray) {
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 var9) {
throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName, "Error resolving array type for " + argName, var9);
}
} else {
elementType = Object.class;
}
}

return this.resolveManagedArray(argName, (List)value, elementType);
} else if (value instanceof ManagedList) {
return this.resolveManagedList(argName, (List)value);
} else if (value instanceof ManagedSet) {
return this.resolveManagedSet(argName, (Set)value);
} else if (value instanceof ManagedMap) {
return this.resolveManagedMap(argName, (Map)value);
} else if (value instanceof ManagedProperties) {
Properties original = (Properties)value;
Properties copy = new Properties();

Object propKey;
Object propValue;
for(Iterator var19 = original.entrySet().iterator(); var19.hasNext(); copy.put(propKey, propValue)) {
Entry<Object, Object> propEntry = (Entry)var19.next();
propKey = propEntry.getKey();
propValue = propEntry.getValue();
if (propKey instanceof TypedStringValue) {
propKey = this.evaluate((TypedStringValue)propKey);
}

if (propValue instanceof TypedStringValue) {
propValue = this.evaluate((TypedStringValue)propValue);
}
}

return copy;
} else if (value instanceof TypedStringValue) {
TypedStringValue typedStringValue = (TypedStringValue)value;
Object valueObject = this.evaluate(typedStringValue);

try {
Class<?> resolvedTargetType = this.resolveTargetType(typedStringValue);
return resolvedTargetType != null ? this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType) : valueObject;
} catch (Throwable var10) {
throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName, "Error converting typed String value for " + argName, var10);
}
} else {
return this.evaluate(value);
}
}

对于非懒加载的对象,由于在容器初始化的时候便完成了依赖注入。这对容器初始化性能会有所影响,但却能够提高应用第一次取得Bean的性能。Spring对于预实例化的处理位于finishBeanFactoryInitialization方法中。实际的处理位于DefaultListableBeanFactory类中的preInstantiateSingletons方法。该方法完成对单件的预实例化,如果需要预实例化,则直接在方法里调用getBean方法。

CATALOG
  1. 1. doGetBean()
  2. 2. createBeanInstance()
  3. 3. populateBean()
  4. 4. applyPropertyValues()
  5. 5. resolveValueIfNecessary()