前言:上篇文章末尾提到createBeanInstance方法中使用工廠方法實例化Bean對象,本文將對該方法進行分析。java
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 }
分析:函數
若是工廠名爲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
#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 }
分析:
#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 }
分析:
#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;
分析:
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;
分析:
這裏就是將構造函數、構造參數進行緩存,也就是最開始爲何要從緩存中獲取的緣由。
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 }
分析:
至此經過工廠方法實例化Bean對象的過程分析完畢,真的是不容易,固然文中還有些方法未詳細分析,後續再進行查漏補缺。
instantiateUsingFactoryMethod方法體很大,可是其核心點就是肯定工廠對象,獲取構造函數和構造參數,最後經過SimpleInstantiationStrategy#instantiate反射執行工廠方法建立bean對象。
by Shawn Chen,2019.04.24日,下午。