【spring源码分析】IOC容器初始化(九)
前言:上篇文章末尾提到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日,下午。