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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
| protected BeanWrapper autowireConstructor(
String beanName, RootBeanDefinition mbd, Constructor<?>[] ctors, Object[] explicitArgs) {
// 创建 ConstructorResolver 对象,并调用其 autowireConstructor 方法
return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}
public BeanWrapper autowireConstructor(final String beanName, final RootBeanDefinition mbd,
Constructor<?>[] chosenCtors, final Object[] explicitArgs) {
// 创建 BeanWrapperImpl 对象
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
Constructor<?> constructorToUse = null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
// 确定参数值列表(argsToUse)
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
else {
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
// 获取已解析的构造方法
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
// 获取已解析的构造方法参数列表
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
// 若 argsToUse 为空,则获取未解析的构造方法参数列表
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
if (argsToResolve != null) {
// 解析参数列表
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
}
}
if (constructorToUse == null) {
boolean autowiring = (chosenCtors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
ConstructorArgumentValues resolvedValues = null;
int minNrOfArgs;
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
else {
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
/*
* 确定构造方法参数数量,比如下面的配置:
* <bean id="persion" class="xyz.coolblog.autowire.Person">
* <constructor-arg index="0" value="xiaoming"/>
* <constructor-arg index="1" value="1"/>
* <constructor-arg index="2" value="man"/>
* </bean>
*
* 此时 minNrOfArgs = maxIndex + 1 = 2 + 1 = 3,除了计算 minNrOfArgs,
* 下面的方法还会将 cargs 中的参数数据转存到 resolvedValues 中
*/
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
// 获取构造方法列表
Constructor<?>[] candidates = chosenCtors;
if (candidates == null) {
Class<?> beanClass = mbd.getBeanClass();
try {
candidates = (mbd.isNonPublicAccessAllowed() ?
beanClass.getDeclaredConstructors() : beanClass.getConstructors());
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Resolution of declared constructors on bean Class [" + beanClass.getName() +
"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
}
}
// 按照构造方法的访问权限级别和参数数量进行排序
AutowireUtils.sortConstructors(candidates);
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Constructor<?>> ambiguousConstructors = null;
LinkedList<UnsatisfiedDependencyException> causes = null;
for (Constructor<?> candidate : candidates) {
Class<?>[] paramTypes = candidate.getParameterTypes();
/*
* 下面的 if 分支的用途是:若匹配到到合适的构造方法了,提前结束 for 循环
* constructorToUse != null 这个条件比较好理解,下面分析一下条件 argsToUse.length > paramTypes.length:
* 前面说到 AutowireUtils.sortConstructors(candidates) 用于对构造方法进行
* 排序,排序规则如下:
* 1. 具有 public 访问权限的构造方法排在非 public 构造方法前
* 2. 参数数量多的构造方法排在前面
*
* 假设现在有一组构造方法按照上面的排序规则进行排序,排序结果如下(省略参数名称):
*
* 1. public Hello(Object, Object, Object)
* 2. public Hello(Object, Object)
* 3. public Hello(Object)
* 4. protected Hello(Integer, Object, Object, Object)
* 5. protected Hello(Integer, Object, Object)
* 6. protected Hello(Integer, Object)
*
* argsToUse = [num1, obj2],可以匹配上的构造方法2和构造方法6。由于构造方法2有
* 更高的访问权限,所以没理由不选他(尽管后者在参数类型上更加匹配)。由于构造方法3
* 参数数量 < argsToUse.length,参数数量上不匹配,也不应该选。所以
* argsToUse.length > paramTypes.length 这个条件用途是:在条件
* constructorToUse != null 成立的情况下,通过判断参数数量与参数值数量
* (argsToUse.length)是否一致,来决定是否提前终止构造方法匹配逻辑。
*/
if (constructorToUse != null && argsToUse.length > paramTypes.length) {
break;
}
/*
* 构造方法参数数量低于配置的参数数量,则忽略当前构造方法,并重试。比如
* argsToUse = [obj1, obj2, obj3, obj4],上面的构造方法列表中,
* 构造方法1、2和3显然不是合适选择,忽略之。
*/
if (paramTypes.length < minNrOfArgs) {
continue;
}
ArgumentsHolder argsHolder;
if (resolvedValues != null) {
try {
/*
* 判断否则方法是否有 ConstructorProperties 注解,若有,则取注解中的
* 值。比如下面的代码:
*
* public class Persion {
* private String name;
* private Integer age;
*
* @ConstructorProperties(value = {"coolblog", "20"})
* public Persion(String name, Integer age) {
* this.name = name;
* this.age = age;
* }
* }
*/
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
if (paramNames == null) {
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
/*
* 获取构造方法参数名称列表,比如有这样一个构造方法:
* public Person(String name, int age, String sex)
*
* 调用 getParameterNames 方法返回 paramNames = [name, age, sex]
*/
paramNames = pnd.getParameterNames(candidate);
}
}
/*
* 创建参数值列表,返回 argsHolder 会包含进行类型转换后的参数值,比如下
* 面的配置:
*
* <bean id="persion" class="xyz.coolblog.autowire.Person">
* <constructor-arg name="name" value="xiaoming"/>
* <constructor-arg name="age" value="1"/>
* <constructor-arg name="sex" value="man"/>
* </bean>
*
* Person 的成员变量 age 是 Integer 类型的,但由于在 Spring 配置中
* 只能配成 String 类型,所以这里要进行类型转换。
*/
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
getUserDeclaredConstructor(candidate), autowiring);
}
catch (UnsatisfiedDependencyException ex) {
if (this.beanFactory.logger.isTraceEnabled()) {
this.beanFactory.logger.trace(
"Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
}
if (causes == null) {
causes = new LinkedList<UnsatisfiedDependencyException>();
}
causes.add(ex);
continue;
}
}
else {
if (paramTypes.length != explicitArgs.length) {
continue;
}
argsHolder = new ArgumentsHolder(explicitArgs);
}
/*
* 计算参数值(argsHolder.arguments)每个参数类型与构造方法参数列表
* (paramTypes)中参数的类型差异量,差异量越大表明参数类型差异越大。参数类型差异
* 越大,表明当前构造方法并不是一个最合适的候选项。引入差异量(typeDiffWeight)
* 变量目的:是将候选构造方法的参数列表类型与参数值列表类型的差异进行量化,通过量化
* 后的数值筛选出最合适的构造方法。
*
* 讲完差异量,再来说说 mbd.isLenientConstructorResolution() 条件。
* 官方的解释是:返回构造方法的解析模式,有宽松模式(lenient mode)和严格模式
* (strict mode)两种类型可选。具体的细节没去研究,就不多说了。
*/
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
if (typeDiffWeight < minTypeDiffWeight) {
constructorToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousConstructors = null;
}
/*
* 如果两个构造方法与参数值类型列表之间的差异量一致,那么这两个方法都可以作为
* 候选项,这个时候就出现歧义了,这里先把有歧义的构造方法放入
* ambiguousConstructors 集合中
*/
else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
if (ambiguousConstructors == null) {
ambiguousConstructors = new LinkedHashSet<Constructor<?>>();
ambiguousConstructors.add(constructorToUse);
}
ambiguousConstructors.add(candidate);
}
}
// 若上面未能筛选出合适的构造方法,这里将抛出 BeanCreationException 异常
if (constructorToUse == null) {
if (causes != null) {
UnsatisfiedDependencyException ex = causes.removeLast();
for (Exception cause : causes) {
this.beanFactory.onSuppressedException(cause);
}
throw ex;
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Could not resolve matching constructor " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
}
/*
* 如果 constructorToUse != null,且 ambiguousConstructors 也不为空,表明解析
* 出了多个的合适的构造方法,此时就出现歧义了。Spring 不会擅自决定使用哪个构造方法,
* 所以抛出异常。
*/
else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Ambiguous constructor matches found in bean '" + beanName + "' " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
ambiguousConstructors);
}
if (explicitArgs == null) {
/*
* 缓存相关信息,比如:
* 1. 已解析出的构造方法对象 resolvedConstructorOrFactoryMethod
* 2. 构造方法参数列表是否已解析标志 constructorArgumentsResolved
* 3. 参数值列表 resolvedConstructorArguments 或 preparedConstructorArguments
*
* 这些信息可用在其他地方,用于进行快捷判断
*/
argsHolderToUse.storeCache(mbd, constructorToUse);
}
}
try {
Object beanInstance;
if (System.getSecurityManager() != null) {
final Constructor<?> ctorToUse = constructorToUse;
final Object[] argumentsToUse = argsToUse;
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
return beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, beanFactory, ctorToUse, argumentsToUse);
}
}, beanFactory.getAccessControlContext());
}
else {
/*
* 调用实例化策略创建实例,默认情况下使用反射创建实例。如果 bean 的配置信息中
* 包含 lookup-method 和 replace-method,则通过 CGLIB 增强 bean 实例
*/
beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
}
// 设置 beanInstance 到 BeanWrapperImpl 对象中
bw.setBeanInstance(beanInstance);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean instantiation via constructor failed", ex);
}
}
|