【spring源碼分析】IOC容器初始化(九)

前言:上篇文章末尾提到createBeanInstance方法中使用工廠方法實例化Bean對象,本文將對該方法進行分析。java


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     }

分析:app

因爲該方法實在是太長了,所以對其進行分段分析。編輯器

#1 首先初始化了BeanwrapperImpl,需確認工廠對象,獲取工廠名稱,若是工廠名不爲null,則走以下流程:ide

 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,則走以下分支:ui

 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         }

分析:this

  • 若是BeanDefinition中沒有解析類,則拋出異常,異常信息也描述得很是清晰:"bean definition的描述中既沒有bean class也沒有工廠的引用。
  • 將factoryClass設置爲BeanDefinition的beanClass,並將isStatic=true,代表可能存在一個靜態工廠。

#2 工廠對象確認後,需確認構造參數。spa

#2.1 若是explicitArgs存在,則直接使用該參數。explicitArgs是調用getBean方法的入參,若是該參數不爲null,則能夠肯定構造函數的參數就是它了。code

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日,下午。

相關文章
相關標籤/搜索