前言:上篇文章末尾提到createBeanInstance方法中使用工廠方法執行個體化Bean對象,本文将對該方法進行分析。
AbstractAutowireCapableBeanFactory#instantiateUsingFactoryMethod
1 protected BeanWrapper instantiateUsingFactoryMethod(
2 String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
3
4 return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
5 }
可以看到這裡是委托給ConstructorResolver來實作的:
1 // ConstructorResolver
2 public BeanWrapper instantiateUsingFactoryMethod(
3 String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
4 // 構造BeanWrapperImpl對象
5 BeanWrapperImpl bw = new BeanWrapperImpl();
6 // 初始化BeanWrapperImpl 向BeanWrapper對象中添加ConversionService對象和屬性編輯器PropertyEditor對象
7 this.beanFactory.initBeanWrapper(bw);
8
9 // 獲得factoryBean、factoryClass、isStatic、factoryBeanName屬性
10 Object factoryBean;
11 Class<?> factoryClass;
12 boolean isStatic;
13
14 String factoryBeanName = mbd.getFactoryBeanName();
15 // 工廠名不為空
16 if (factoryBeanName != null) {
17 // 如果工廠名和beanName相等,則抛出BeanDefinitionStoreException異常
18 if (factoryBeanName.equals(beanName)) {
19 throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
20 "factory-bean reference points back to the same bean definition");
21 }
22 // 擷取工廠執行個體
23 factoryBean = this.beanFactory.getBean(factoryBeanName);
24 // 如果是單例模式,并且已經緩存中已經存在beanName則抛出異常
25 if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
26 throw new ImplicitlyAppearedSingletonException();
27 }
28 factoryClass = factoryBean.getClass();
29 isStatic = false;
30 } else {
31 // 工廠名為空,則其可能是一個靜态工廠
32 // 靜态工廠建立bean,必須要提供工廠的全類名
33 // It's a static factory method on the bean class.
34 if (!mbd.hasBeanClass()) {
35 throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
36 "bean definition declares neither a bean class nor a factory-bean reference");
37 }
38 factoryBean = null;
39 factoryClass = mbd.getBeanClass();
40 isStatic = true;
41 }
42
43 // 獲得factoryMethodToUse、argsHolderToUse、argsToUse屬性
44 Method factoryMethodToUse = null;
45 ArgumentsHolder argsHolderToUse = null;
46 Object[] argsToUse = null;
47
48 // 如果指定了構造參數則直接使用
49 // 在調用getBean方法的時候指定方法參數
50 if (explicitArgs != null) {
51 argsToUse = explicitArgs;
52 } else {
53 // 沒有指定,則嘗試從配置檔案中解析
54 Object[] argsToResolve = null;
55 // 同步
56 synchronized (mbd.constructorArgumentLock) {
57 // 擷取緩存中的構造函數或者工廠方法
58 factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
59 if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
60 // 擷取緩存中的構造參數
61 // Found a cached factory method...
62 argsToUse = mbd.resolvedConstructorArguments;
63 if (argsToUse == null) {
64 argsToResolve = mbd.preparedConstructorArguments;
65 }
66 }
67 }
68 // 緩存中存在,則解析存儲在BeanDefinition中的參數
69 // 如給定方法的構造函數 f(int ,int),通過此方法後就會把配置檔案中的("1","1")轉換為(1,1)
70 // 緩存中的值可能是原始值,也可能是最終值
71 if (argsToResolve != null) {
72 argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
73 }
74 }
75
76 if (factoryMethodToUse == null || argsToUse == null) {
77 // Need to determine the factory method...
78 // Try all methods with this name to see if they match the given arguments.
79 // 擷取工廠方法的類的全類名
80 factoryClass = ClassUtils.getUserClass(factoryClass);
81
82 List<Method> candidateList = null;
83 // 同步
84 if (mbd.isFactoryMethodUnique) {
85 // 擷取工廠方法
86 if (factoryMethodToUse == null) {
87 factoryMethodToUse = mbd.getResolvedFactoryMethod();
88 }
89 // 擷取所有待定的工廠方法
90 if (factoryMethodToUse != null) {
91 candidateList = Collections.singletonList(factoryMethodToUse);
92 }
93 }
94 // 如果工廠方法為空,則通過getCandidateMethods擷取所有的待定方法
95 if (candidateList == null) {
96 candidateList = new ArrayList<>();
97 Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
98 for (Method candidate : rawCandidates) {
99 if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
100 candidateList.add(candidate);
101 }
102 }
103 }
104
105 // 通過工廠方法建立bean
106 if (candidateList.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
107 Method uniqueCandidate = candidateList.get(0);
108 if (uniqueCandidate.getParameterCount() == 0) {
109 mbd.factoryMethodToIntrospect = uniqueCandidate;
110 synchronized (mbd.constructorArgumentLock) {
111 mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
112 mbd.constructorArgumentsResolved = true;
113 mbd.resolvedConstructorArguments = EMPTY_ARGS;
114 }
115 bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
116 return bw;
117 }
118 }
119
120 Method[] candidates = candidateList.toArray(new Method[0]);
121 // 排序構造函數
122 // public構造函數優先參數數量降序,非public構造函數參數數量降序
123 AutowireUtils.sortFactoryMethods(candidates);
124
125 // 用于承載解析後的構造函數參數的值
126 ConstructorArgumentValues resolvedValues = null;
127 boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
128 int minTypeDiffWeight = Integer.MAX_VALUE;
129 Set<Method> ambiguousFactoryMethods = null;
130
131 int minNrOfArgs;
132 if (explicitArgs != null) {
133 minNrOfArgs = explicitArgs.length;
134 } else {
135 // We don't have arguments passed in programmatically, so we need to resolve the
136 // arguments specified in the constructor arguments held in the bean definition.
137 // getBean沒有傳遞參數,則需要解析儲存在BeanDefinition構造函數中指定的參數
138 if (mbd.hasConstructorArgumentValues()) {
139 // 構造函數參數
140 ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
141 resolvedValues = new ConstructorArgumentValues();
142 // 解析構造函數參數
143 // 将bean的構造函數解析為resolvedValues對象,其中會涉及到其他的bean
144 minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
145 } else {
146 minNrOfArgs = 0;
147 }
148 }
149
150 // 記錄UnsatisfiedDependencyException異常集合
151 LinkedList<UnsatisfiedDependencyException> causes = null;
152
153 // 周遊candidates
154 for (Method candidate : candidates) {
155 // 方法體參數
156 Class<?>[] paramTypes = candidate.getParameterTypes();
157
158 if (paramTypes.length >= minNrOfArgs) {
159 // 儲存參數對象
160 ArgumentsHolder argsHolder;
161 // getBean()傳遞了參數
162 if (explicitArgs != null) {
163 // Explicit arguments given -> arguments length must match exactly.
164 // 顯示給定參數,參數長度必須完全比對
165 if (paramTypes.length != explicitArgs.length) {
166 continue;
167 }
168 // 根據參數建立參數持有者ArgumentsHolder對象
169 argsHolder = new ArgumentsHolder(explicitArgs);
170 } else {
171 // Resolved constructor arguments: type conversion and/or autowiring necessary.
172 // 根據提供的參數,解析構造函數
173 try {
174 String[] paramNames = null;
175 // 擷取ParameterNameDiscoverer對象
176 // ParameterNameDiscoverer用于解析方法和構造函數的參數名,為參數名稱探測器
177 ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
178 // 擷取指定構造函數的參數名
179 if (pnd != null) {
180 paramNames = pnd.getParameterNames(candidate);
181 }
182 // 在已解析構造函數參數值的情況下,建立一個參數持有者ArgumentsHolder對象
183 argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
184 paramTypes, paramNames, candidate, autowiring, candidates.length == 1);
185 } catch (UnsatisfiedDependencyException ex) {
186 if (logger.isTraceEnabled()) {
187 logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex);
188 }
189 // Swallow and try next overloaded factory method.
190 if (causes == null) {
191 causes = new LinkedList<>();
192 }
193 // 發生UnsatisfiedDependencyException異常,添加到causes中
194 causes.add(ex);
195 continue;
196 }
197 }
198
199 // isLenientConstructorResolution判斷解析構造函數的時候是否以寬松模式還是嚴格模式
200 // 寬松模式:使用具有"最接近的模式"進行比對
201 // 嚴格模式:解析構造函數時,必須所有的都需要比對,否則抛出異常
202 int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
203 argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
204 // Choose this factory method if it represents the closest match.
205 // 代表最接近的類型比對,選擇作為構造函數
206 if (typeDiffWeight < minTypeDiffWeight) {
207 factoryMethodToUse = candidate;
208 argsHolderToUse = argsHolder;
209 argsToUse = argsHolder.arguments;
210 minTypeDiffWeight = typeDiffWeight;
211 ambiguousFactoryMethods = null;
212 }
213 // Find out about ambiguity: In case of the same type difference weight
214 // for methods with the same number of parameters, collect such candidates
215 // and eventually raise an ambiguity exception.
216 // However, only perform that check in non-lenient constructor resolution mode,
217 // and explicitly ignore overridden methods (with the same parameter signature).
218 // 如果具有相同參數數量的方法具有相同的類型差異權重,則收集此類型選項
219 // 但是僅在非寬松模式構造函數解析模式下執行該檢查,并顯示忽略重寫方法(具有相同的參數簽名)
220 else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
221 !mbd.isLenientConstructorResolution() &&
222 paramTypes.length == factoryMethodToUse.getParameterCount() &&
223 !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
224 // 查找多個可比對的方法
225 if (ambiguousFactoryMethods == null) {
226 ambiguousFactoryMethods = new LinkedHashSet<>();
227 ambiguousFactoryMethods.add(factoryMethodToUse);
228 }
229 ambiguousFactoryMethods.add(candidate);
230 }
231 }
232 }
233
234 // 沒有可執行的工廠方法,則抛出異常
235 if (factoryMethodToUse == null || argsToUse == null) {
236 if (causes != null) {
237 UnsatisfiedDependencyException ex = causes.removeLast();
238 for (Exception cause : causes) {
239 this.beanFactory.onSuppressedException(cause);
240 }
241 throw ex;
242 }
243 List<String> argTypes = new ArrayList<>(minNrOfArgs);
244 if (explicitArgs != null) {
245 for (Object arg : explicitArgs) {
246 argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
247 }
248 } else if (resolvedValues != null) {
249 Set<ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount());
250 valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());
251 valueHolders.addAll(resolvedValues.getGenericArgumentValues());
252 for (ValueHolder value : valueHolders) {
253 String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :
254 (value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));
255 argTypes.add(argType);
256 }
257 }
258 String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
259 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
260 "No matching factory method found: " +
261 (mbd.getFactoryBeanName() != null ?
262 "factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
263 "factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
264 "Check that a method with the specified name " +
265 (minNrOfArgs > 0 ? "and arguments " : "") +
266 "exists and that it is " +
267 (isStatic ? "static" : "non-static") + ".");
268 } else if (void.class == factoryMethodToUse.getReturnType()) {
269 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
270 "Invalid factory method '" + mbd.getFactoryMethodName() +
271 "': needs to have a non-void return type!");
272 } else if (ambiguousFactoryMethods != null) {
273 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
274 "Ambiguous factory method matches found in bean '" + beanName + "' " +
275 "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
276 ambiguousFactoryMethods);
277 }
278
279 // 将解析的構造函數加入緩存
280 if (explicitArgs == null && argsHolderToUse != null) {
281 mbd.factoryMethodToIntrospect = factoryMethodToUse;
282 argsHolderToUse.storeCache(mbd, factoryMethodToUse);
283 }
284 }
285
286 // 建立bean對象,并設定到BeanWrapperImpl中
287 bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
288 return bw;
289 }
分析:
由于該方法實在是太長了,是以對其進行分段分析。
#1 首先初始化了BeanwrapperImpl,需确認工廠對象,擷取工廠名稱,如果工廠名不為null,則走如下流程:
1 String factoryBeanName = mbd.getFactoryBeanName();
2 // 工廠名不為空
3 if (factoryBeanName != null) {
4 // 如果工廠名和beanName相等,則抛出BeanDefinitionStoreException異常
5 if (factoryBeanName.equals(beanName)) {
6 throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
7 "factory-bean reference points back to the same bean definition");
8 }
9 // 擷取工廠執行個體
10 factoryBean = this.beanFactory.getBean(factoryBeanName);
11 // 如果是單例模式,并且已經緩存中已經存在beanName則抛出異常
12 if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
13 throw new ImplicitlyAppearedSingletonException();
14 }
15 factoryClass = factoryBean.getClass();
16 isStatic = false;
17 }
- 如果factoryBeanName與beanName一樣,則抛出BeanDefinitionStoreException異常。
- 然後通過AbstractBeanFactory#getBean方法擷取工廠執行個體對象。
- 如果BeanDefinition為單例模式,且singletonObjects緩存中已經存在該bean對象了,則抛出異常。因為單例模式下且緩存中存在是不需要再次建立bean對象的,單例模式的bean隻會執行個體化一次。
如果工廠名為null,則走如下分支:
1 else {
2 // 工廠名為空,則其可能是一個靜态工廠
3 // 靜态工廠建立bean,必須要提供工廠的全類名
4 // It's a static factory method on the bean class.
5 if (!mbd.hasBeanClass()) {
6 throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
7 "bean definition declares neither a bean class nor a factory-bean reference");
8 }
9 factoryBean = null;
10 factoryClass = mbd.getBeanClass();
11 isStatic = true;
12 }
- 如果BeanDefinition中沒有解析類,則抛出異常,異常資訊也描述得非常清晰:"bean definition的描述中既沒有bean class也沒有工廠的引用。
- 将factoryClass設定為BeanDefinition的beanClass,并将isStatic=true,表明可能存在一個靜态工廠。
#2 工廠對象确認後,需确認構造參數。
#2.1 如果explicitArgs存在,則直接使用該參數。explicitArgs是調用getBean方法的入參,如果該參數不為null,則可以确定構造函數的參數就是它了。
1 // 确定構造參數
2 // 如果getBean()已傳遞,則直接使用
3 if (explicitArgs != null) {
4 argsToUse = explicitArgs;
5 }
#2.2 如果未傳入構造參數,則走如下分支:
1 else {
2 // 沒有指定,則嘗試從緩存中擷取
3 Object[] argsToResolve = null;
4 // 同步
5 synchronized (mbd.constructorArgumentLock) {
6 // 擷取緩存中的構造函數或者工廠方法
7 factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
8 if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
9 // 擷取緩存中的構造參數
10 // Found a cached factory method...
11 argsToUse = mbd.resolvedConstructorArguments;
12 if (argsToUse == null) {
13 argsToResolve = mbd.preparedConstructorArguments;
14 }
15 }
16 }
17 // 緩存中存在,則解析存儲在BeanDefinition中的參數
18 // 如給定方法的構造函數 f(int ,int),通過此方法後就會把配置檔案中的("1","1")轉換為(1,1)
19 // 緩存中的值可能是原始值,也可能是最終值
20 if (argsToResolve != null) {
21 argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
22 }
23 }
整個流程其實就是嘗試從緩存中擷取構造函數參數,如果存在則通過resolvePreparedArguments進行轉換,由于緩存中的值可能是最終值,也可能不是最終值。比如構造函數中的類型為Integer類型的1,但緩存中的類型有可能是String類型的"1",是以即便是從緩存中得到了構造參數,也需要經過一番的類型轉換才能確定參數類型完全對應。關于resolvePreparedArguments函數的解析,将在後續文章中展現。
#2.3 如果緩存中未擷取到構造參數,則走如下分支:
1 if (factoryMethodToUse == null || argsToUse == null) {
2 // Need to determine the factory method...
3 // Try all methods with this name to see if they match the given arguments.
4 // 擷取工廠方法的類的全類名
5 factoryClass = ClassUtils.getUserClass(factoryClass);
6
7 List<Method> candidateList = null;
8 // 同步
9 if (mbd.isFactoryMethodUnique) {
10 // 擷取工廠方法
11 if (factoryMethodToUse == null) {
12 factoryMethodToUse = mbd.getResolvedFactoryMethod();
13 }
14 // 擷取所有待定的工廠方法
15 if (factoryMethodToUse != null) {
16 candidateList = Collections.singletonList(factoryMethodToUse);
17 }
18 }
19 // 如果工廠方法為空,則通過getCandidateMethods擷取所有的待定方法
20 if (candidateList == null) {
21 candidateList = new ArrayList<>();
22 Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
23 for (Method candidate : rawCandidates) {
24 if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
25 candidateList.add(candidate);
26 }
27 }
28 }
29
30 // 通過工廠方法建立bean
31 if (candidateList.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
32 Method uniqueCandidate = candidateList.get(0);
33 if (uniqueCandidate.getParameterCount() == 0) {
34 mbd.factoryMethodToIntrospect = uniqueCandidate;
35 synchronized (mbd.constructorArgumentLock) {
36 mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
37 mbd.constructorArgumentsResolved = true;
38 mbd.resolvedConstructorArguments = EMPTY_ARGS;
39 }
40 bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
41 return bw;
42 }
43 }
如果在緩存中未到構造參數,則嘗試通過native方法擷取工廠方法類的全類名,如果得到工廠方法隻有一個時,則通過instantiate方法執行個體化bean,然後注入到BeanWrapperImpl中,直接傳回。
instantiate方法會在後面進行分析。
#2.4 當上述分支都不滿足,則走如下分支:通過提取配置檔案中的資訊來執行建構操作(代碼還是有些長,分段來看):
1 Method[] candidates = candidateList.toArray(new Method[0]);
2 // 排序構造函數
3 // public構造函數優先參數數量降序,非public構造函數參數數量降序
4 AutowireUtils.sortFactoryMethods(candidates);
5
6 // 用于承載解析後的構造函數參數的值
7 ConstructorArgumentValues resolvedValues = null;
8 boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
9 int minTypeDiffWeight = Integer.MAX_VALUE;
10 Set<Method> ambiguousFactoryMethods = null;
11
12 int minNrOfArgs;
13 if (explicitArgs != null) {
14 minNrOfArgs = explicitArgs.length;
15 } else {
16 // We don't have arguments passed in programmatically, so we need to resolve the
17 // arguments specified in the constructor arguments held in the bean definition.
18 // getBean沒有傳遞參數,則需要解析儲存在BeanDefinition構造函數中指定的參數
19 if (mbd.hasConstructorArgumentValues()) {
20 // 構造函數參數
21 ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
22 resolvedValues = new ConstructorArgumentValues();
23 // 解析構造函數參數
24 // 将bean的構造函數解析為resolvedValues對象,其中會涉及到其他的bean
25 minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
26 } else {
27 minNrOfArgs = 0;
28 }
29 }
- 首先對工廠方法進行排序處理,排序規則:public工廠方法優先,參數數量降序,然後非public工廠方法優先,參數數量降序。
- 如果入參中帶有構造參數,則直接擷取構造參數的個數。
- 否則需從BeanDefinition中擷取構造函數,并進行解析。xml配置檔案的構造函數解析在加載BeanDefinition的過程中有提及。
- 然後通過resolveConstructorArguments解析構造函數,并傳回構造參數的最小個數。resolveConstructorArguments函數目前這裡不做分析。
#2.4.1 上步中确定了構造參數,接下來進行構造函數的确定:
1 // 周遊candidates
2 for (Method candidate : candidates) {
3 // 方法體參數
4 Class<?>[] paramTypes = candidate.getParameterTypes();
5
6 if (paramTypes.length >= minNrOfArgs) {
7 // 儲存參數對象
8 ArgumentsHolder argsHolder;
9 // getBean()傳遞了參數
10 if (explicitArgs != null) {
11 // Explicit arguments given -> arguments length must match exactly.
12 // 顯示給定參數,參數長度必須完全比對
13 if (paramTypes.length != explicitArgs.length) {
14 continue;
15 }
16 // 根據參數建立參數持有者ArgumentsHolder對象
17 argsHolder = new ArgumentsHolder(explicitArgs);
18 } else {
19 // Resolved constructor arguments: type conversion and/or autowiring necessary.
20 // 根據提供的參數,解析構造函數
21 try {
22 String[] paramNames = null;
23 // 擷取ParameterNameDiscoverer對象
24 // ParameterNameDiscoverer用于解析方法和構造函數的參數名,為參數名稱探測器
25 ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
26 // 擷取指定構造函數的參數名
27 if (pnd != null) {
28 paramNames = pnd.getParameterNames(candidate);
29 }
30 // 在已解析構造函數參數值的情況下,建立一個參數持有者ArgumentsHolder對象
31 argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
32 paramTypes, paramNames, candidate, autowiring, candidates.length == 1);
33 } catch (UnsatisfiedDependencyException ex) {
34 if (logger.isTraceEnabled()) {
35 logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex);
36 }
37 // Swallow and try next overloaded factory method.
38 if (causes == null) {
39 causes = new LinkedList<>();
40 }
41 // 發生UnsatisfiedDependencyException異常,添加到causes中
42 causes.add(ex);
43 continue;
44 }
45 }
46
47 // isLenientConstructorResolution判斷解析構造函數的時候是否以寬松模式還是嚴格模式
48 // 寬松模式:使用具有"最接近的模式"進行比對
49 // 嚴格模式:解析構造函數時,必須所有的都需要比對,否則抛出異常
50 int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
51 argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
52 // Choose this factory method if it represents the closest match.
53 // 代表最接近的類型比對,選擇作為構造函數
54 if (typeDiffWeight < minTypeDiffWeight) {
55 factoryMethodToUse = candidate;
56 argsHolderToUse = argsHolder;
57 argsToUse = argsHolder.arguments;
58 minTypeDiffWeight = typeDiffWeight;
59 ambiguousFactoryMethods = null;
60 }
61 // Find out about ambiguity: In case of the same type difference weight
62 // for methods with the same number of parameters, collect such candidates
63 // and eventually raise an ambiguity exception.
64 // However, only perform that check in non-lenient constructor resolution mode,
65 // and explicitly ignore overridden methods (with the same parameter signature).
66 // 如果具有相同參數數量的方法具有相同的類型差異權重,則收集此類型選項
67 // 但是僅在非寬松模式構造函數解析模式下執行該檢查,并顯示忽略重寫方法(具有相同的參數簽名)
68 else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
69 !mbd.isLenientConstructorResolution() &&
70 paramTypes.length == factoryMethodToUse.getParameterCount() &&
71 !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
72 // 查找多個可比對的方法
73 if (ambiguousFactoryMethods == null) {
74 ambiguousFactoryMethods = new LinkedHashSet<>();
75 ambiguousFactoryMethods.add(factoryMethodToUse);
76 }
77 ambiguousFactoryMethods.add(candidate);
78 }
79 }
80 }
分析:
- 周遊所有構造函數。
- 如果方法體參數大于等于最小參數個數,則判斷是否傳入了構造參數,如果是,則根據入參建立參數持有者對象ArgumentsHolder;否則通過方法體擷取指定構造函數的參數,并建立參數持有者對象ArgumentsHolder。
- 接着确定構造函數的解析是使用寬松模式還是嚴格模式。
- 嚴格模式:解析構造函數時,必須所有參數都需要比對,否則抛出異常。
- 寬松模式:使用具有”最接近的模式”進行比對。
#3.在參數與工廠構造函數确認好後,就可以進行bean的執行個體化了
1 // 沒有可執行的工廠方法,則抛出異常
2 if (factoryMethodToUse == null || argsToUse == null) {
3 if (causes != null) {
4 UnsatisfiedDependencyException ex = causes.removeLast();
5 for (Exception cause : causes) {
6 this.beanFactory.onSuppressedException(cause);
7 }
8 throw ex;
9 }
10 List<String> argTypes = new ArrayList<>(minNrOfArgs);
11 if (explicitArgs != null) {
12 for (Object arg : explicitArgs) {
13 argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
14 }
15 } else if (resolvedValues != null) {
16 Set<ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount());
17 valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());
18 valueHolders.addAll(resolvedValues.getGenericArgumentValues());
19 for (ValueHolder value : valueHolders) {
20 String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :
21 (value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));
22 argTypes.add(argType);
23 }
24 }
25 String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
26 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
27 "No matching factory method found: " +
28 (mbd.getFactoryBeanName() != null ?
29 "factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
30 "factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
31 "Check that a method with the specified name " +
32 (minNrOfArgs > 0 ? "and arguments " : "") +
33 "exists and that it is " +
34 (isStatic ? "static" : "non-static") + ".");
35 } else if (void.class == factoryMethodToUse.getReturnType()) {
36 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
37 "Invalid factory method '" + mbd.getFactoryMethodName() +
38 "': needs to have a non-void return type!");
39 } else if (ambiguousFactoryMethods != null) {
40 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
41 "Ambiguous factory method matches found in bean '" + beanName + "' " +
42 "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
43 ambiguousFactoryMethods);
44 }
45
46 // 将解析的構造函數加入緩存
47 if (explicitArgs == null && argsHolderToUse != null) {
48 mbd.factoryMethodToIntrospect = factoryMethodToUse;
49 argsHolderToUse.storeCache(mbd, factoryMethodToUse);
50 }
51 }
52
53 // 建立bean對象,并設定到BeanWrapperImpl中
54 bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
55 return bw;
- 如果工廠方法為空或構造參數為空,經過一系列異常判斷後,最後會将解析的構造函數加入緩存。
- 然後通過instantiate方法建立bean對象,并注入到BeanWrapperImpl中,最後傳回bw。
1 // ConstructorResolver
2
3 public void storeCache(RootBeanDefinition mbd, Executable constructorOrFactoryMethod) {
4 synchronized (mbd.constructorArgumentLock) {
5 mbd.resolvedConstructorOrFactoryMethod = constructorOrFactoryMethod;
6 mbd.constructorArgumentsResolved = true;
7 if (this.resolveNecessary) {
8 mbd.preparedConstructorArguments = this.preparedArguments;
9 } else {
10 mbd.resolvedConstructorArguments = this.arguments;
11 }
12 }
13 }
14
15 // RootBeanDefinition.java
16 /**
17 * 構造函數的緩存鎖
18 * Common lock for the four constructor fields below.
19 */
20 final Object constructorArgumentLock = new Object();
21
22 /**
23 * 緩存已經解析的構造函數或工廠方法<br/>
24 * Package-visible field for caching the resolved constructor or factory method.
25 */
26 @Nullable
27 Executable resolvedConstructorOrFactoryMethod;
28
29 /**
30 * 标記字段:标記構造函數、參數是否已經解析,預設為false<br/>
31 * Package-visible field that marks the constructor arguments as resolved.
32 */
33 boolean constructorArgumentsResolved = false;
34
35 /**
36 * 緩存已經解析的構造函數參數,包括可見字段<br/>
37 * Package-visible field for caching fully resolved constructor arguments.
38 */
39 @Nullable
40 Object[] resolvedConstructorArguments;
這裡就是将構造函數、構造參數進行緩存,也就是最開始為什麼要從緩存中擷取的原因。
ConstructorResolver#instantiate
1 private Object instantiate(String beanName, RootBeanDefinition mbd,
2 @Nullable Object factoryBean, Method factoryMethod, Object[] args) {
3
4 try {
5
6 if (System.getSecurityManager() != null) {
7 return AccessController.doPrivileged((PrivilegedAction<Object>) () ->
8 this.beanFactory.getInstantiationStrategy().instantiate(
9 mbd, beanName, this.beanFactory, factoryBean, factoryMethod, args),
10 this.beanFactory.getAccessControlContext());
11 } else {
12 return this.beanFactory.getInstantiationStrategy().instantiate(
13 mbd, beanName, this.beanFactory, factoryBean, factoryMethod, args);
14 }
15 } catch (Throwable ex) {
16 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
17 "Bean instantiation via factory method failed", ex);
18 }
19 }
該方法就是建立bean對象的方法,這裡會委托調用SimpleInstantiationStrategy#instantiate方法。
1 public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
2 @Nullable Object factoryBean, final Method factoryMethod, Object... args) {
3
4 try {
5 // 設定method可通路
6 if (System.getSecurityManager() != null) {
7 AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
8 ReflectionUtils.makeAccessible(factoryMethod);
9 return null;
10 });
11 } else {
12 ReflectionUtils.makeAccessible(factoryMethod);
13 }
14
15 // 獲得原method對象
16 Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
17 try {
18 // 設定新的method對象到currentlyInvokedFactoryMethod中
19 currentlyInvokedFactoryMethod.set(factoryMethod);
20 // 建立bean對象 通過反射執行工廠方法并傳回建立的bean對象
21 Object result = factoryMethod.invoke(factoryBean, args);
22 // 未建立,則建立NullBean對象
23 if (result == null) {
24 result = new NullBean();
25 }
26 return result;
27 } finally {
28 // 設定老的method對象到currentlyInvokedFactoryMethod中
29 if (priorInvokedFactoryMethod != null) {
30 currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
31 } else {
32 currentlyInvokedFactoryMethod.remove();
33 }
34 }
35 } catch (IllegalArgumentException ex) {
36 throw new BeanInstantiationException(factoryMethod,
37 "Illegal arguments to factory method '" + factoryMethod.getName() + "'; " +
38 "args: " + StringUtils.arrayToCommaDelimitedString(args), ex);
39 } catch (IllegalAccessException ex) {
40 throw new BeanInstantiationException(factoryMethod,
41 "Cannot access factory method '" + factoryMethod.getName() + "'; is it public?", ex);
42 } catch (InvocationTargetException ex) {
43 String msg = "Factory method '" + factoryMethod.getName() + "' threw exception";
44 if (bd.getFactoryBeanName() != null && owner instanceof ConfigurableBeanFactory &&
45 ((ConfigurableBeanFactory) owner).isCurrentlyInCreation(bd.getFactoryBeanName())) {
46 msg = "Circular reference involving containing bean '" + bd.getFactoryBeanName() + "' - consider " +
47 "declaring the factory method as static for independence from its containing instance. " + msg;
48 }
49 throw new BeanInstantiationException(factoryMethod, msg, ex.getTargetException());
50 }
51 }
- 首先設定方法的可通路性。
- 然後更新currentlyInvokedFactoryMethod緩存的方法。
- 核心點是通過反射執行工廠方法建立bean對象。
- 最後再次更新currentlyInvokedFactoryMethod。
至此通過工廠方法執行個體化Bean對象的過程分析完畢,真的是不容易,當然文中還有些方法未詳細分析,後續再進行查漏補缺。
總結
instantiateUsingFactoryMethod方法體很大,但是其核心點就是确定工廠對象,擷取構造函數和構造參數,最後通過SimpleInstantiationStrategy#instantiate反射執行工廠方法建立bean對象。
by Shawn Chen,2019.04.24日,下午。