且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

【死磕 Spring】—– IOC 之 Factory 实例化 bean

更新时间:2022-09-13 14:57:49

这篇我们关注创建 bean 过程中的第一个步骤:实例化 bean,对应的方法为: createBeanInstance(),如下:

  1. protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {

  2. // 解析 bean,将 bean 类名解析为 class 引用

  3. Class<?> beanClass = resolveBeanClass(mbd, beanName);


  4. if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {

  5. throw new BeanCreationException(mbd.getResourceDescription(), beanName,

  6. "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());

  7. }


  8. // 如果存在 Supplier 回调,则使用给定的回调方法初始化策略

  9. Supplier<?> instanceSupplier = mbd.getInstanceSupplier();

  10. if (instanceSupplier != null) {

  11. return obtainFromSupplier(instanceSupplier, beanName);

  12. }


  13. // 如果工厂方法不为空,则使用工厂方法初始化策略

  14. if (mbd.getFactoryMethodName() != null) {

  15. return instantiateUsingFactoryMethod(beanName, mbd, args);

  16. }


  17. boolean resolved = false;

  18. boolean autowireNecessary = false;

  19. if (args == null) {

  20. // constructorArgumentLock 构造函数的常用锁

  21. synchronized (mbd.constructorArgumentLock) {

  22. // 如果已缓存的解析的构造函数或者工厂方法不为空,则可以利用构造函数解析

  23. // 因为需要根据参数确认到底使用哪个构造函数,该过程比较消耗性能,所有采用缓存机制

  24. if (mbd.resolvedConstructorOrFactoryMethod != null) {

  25. resolved = true;

  26. autowireNecessary = mbd.constructorArgumentsResolved;

  27. }

  28. }

  29. }

  30. // 已经解析好了,直接注入即可

  31. if (resolved) {

  32. // 自动注入,调用构造函数自动注入

  33. if (autowireNecessary) {

  34. return autowireConstructor(beanName, mbd, null, null);

  35. }

  36. else {

  37. // 使用默认构造函数构造

  38. return instantiateBean(beanName, mbd);

  39. }

  40. }


  41. // 确定解析的构造函数

  42. // 主要是检查已经注册的 SmartInstantiationAwareBeanPostProcessor

  43. Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);

  44. if (ctors != null ||

  45. mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||

  46. mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {

  47. // 构造函数自动注入

  48. return autowireConstructor(beanName, mbd, ctors, args);

  49. }


  50. //使用默认构造函数注入

  51. return instantiateBean(beanName, mbd);

  52. }

实例化 bean 是一个复杂的过程,其主要的逻辑为:

如果存在 Supplier 回调,则调用 obtainFromSupplier() 进行初始化

如果存在工厂方法,则使用工厂方法进行初始化

首先判断缓存,如果缓存中存在,即已经解析过了,则直接使用已经解析了的,根据 constructorArgumentsResolved 参数来判断是使用构造函数自动注入还是默认构造函数

如果缓存中没有,则需要先确定到底使用哪个构造函数来完成解析工作,因为一个类有多个构造函数,每个构造函数都有不同的构造参数,所以需要根据参数来锁定构造函数并完成初始化,如果存在参数则使用相应的带有参数的构造函数,否则使用默认构造函数。

下面就上面四种情况做分别说明。

obtainFromSupplier()


  1. Supplier<?> instanceSupplier = mbd.getInstanceSupplier();

  2. if (instanceSupplier != null) {

  3. return obtainFromSupplier(instanceSupplier, beanName);

  4. }

首先从 BeanDefinition 中获取 Supplier,如果不为空,则调用 obtainFromSupplier() 。那么 Supplier 是什么呢?在这之前也没有提到过这个字段。


  1. public interface Supplier<T> {

  2. T get();

  3. }

Supplier 接口仅有一个功能性的 get(),该方法会返回一个 T 类型的对象,有点儿类似工厂方法。这个接口有什么作用?用于指定创建 bean 的回调,如果我们设置了这样的回调,那么其他的构造器或者工厂方法都会没有用。在什么设置该参数呢?Spring 提供了相应的 setter 方法,如下:


  1. public void setInstanceSupplier(@Nullable Supplier<?> instanceSupplier) {

  2. this.instanceSupplier = instanceSupplier;

  3. }

在构造 BeanDefinition 的时候设置了该值,如下(以 RootBeanDefinition 为例):


  1. public <T> RootBeanDefinition(@Nullable Class<T> beanClass, String scope, @Nullable Supplier<T> instanceSupplier) {

  2. super();

  3. setBeanClass(beanClass);

  4. setScope(scope);

  5. setInstanceSupplier(instanceSupplier);

  6. }

如果设置了 instanceSupplier 则调用 obtainFromSupplier() 完成 bean 的初始化,如下:


  1. protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) {

  2. String outerBean = this.currentlyCreatedBean.get();

  3. this.currentlyCreatedBean.set(beanName);

  4. Object instance;

  5. try {

  6. // 调用 Supplier 的 get(),返回一个对象

  7. instance = instanceSupplier.get();

  8. }

  9. finally {

  10. if (outerBean != null) {

  11. this.currentlyCreatedBean.set(outerBean);

  12. }

  13. else {

  14. this.currentlyCreatedBean.remove();

  15. }

  16. }

  17. // 根据对象构造 BeanWrapper 对象

  18. BeanWrapper bw = new BeanWrapperImpl(instance);

  19. // 初始化 BeanWrapper

  20. initBeanWrapper(bw);

  21. return bw;

  22. }

代码很简单,调用 调用 Supplier 的 get() 方法,获得一个 bean 实例对象,然后根据该实例对象构造一个 BeanWrapper 对象 bw,最后初始化该对象。有关于 BeanWrapper 后面专门出文讲解。

instantiateUsingFactoryMethod()

如果存在工厂方法,则调用 instantiateUsingFactoryMethod() 完成 bean 的初始化工作(方法实现比较长,细节比较复杂,各位就硬着头皮看吧)。


  1. protected BeanWrapper instantiateUsingFactoryMethod(

  2. String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {

  3. return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);

  4. }

构造一个 ConstructorResolver 对象,然后调用其 instantiateUsingFactoryMethod() 方法。ConstructorResolver 是构造方法或者工厂类初始化 bean 的委托类。


  1. public BeanWrapper instantiateUsingFactoryMethod(

  2. final String beanName, final RootBeanDefinition mbd, @Nullable final Object[] explicitArgs) {


  3. // 构造 BeanWrapperImpl 对象

  4. BeanWrapperImpl bw = new BeanWrapperImpl();

  5. // 初始化 BeanWrapperImpl

  6. // 向BeanWrapper对象中添加 ConversionService 对象和属性编辑器 PropertyEditor 对象

  7. //

  8. this.beanFactory.initBeanWrapper(bw);


  9. Object factoryBean;

  10. Class<?> factoryClass;

  11. boolean isStatic;


  12. // 工厂名不为空

  13. String factoryBeanName = mbd.getFactoryBeanName();

  14. if (factoryBeanName != null) {

  15. if (factoryBeanName.equals(beanName)) {

  16. throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,

  17. "factory-bean reference points back to the same bean definition");

  18. }

  19. // 获取工厂实例

  20. factoryBean = this.beanFactory.getBean(factoryBeanName);

  21. if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {

  22. throw new ImplicitlyAppearedSingletonException();

  23. }

  24. factoryClass = factoryBean.getClass();

  25. isStatic = false;

  26. }

  27. else {

  28. // 工厂名为空,则其可能是一个静态工厂


  29. // 静态工厂创建bean,必须要提供工厂的全类名

  30. if (!mbd.hasBeanClass()) {

  31. throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,

  32. "bean definition declares neither a bean class nor a factory-bean reference");

  33. }

  34. factoryBean = null;

  35. factoryClass = mbd.getBeanClass();

  36. isStatic = true;

  37. }


  38. // 工厂方法

  39. Method factoryMethodToUse = null;

  40. ConstructorResolver.ArgumentsHolder argsHolderToUse = null;

  41. // 参数

  42. Object[] argsToUse = null;


  43. // 工厂方法的参数

  44. // 如果指定了构造参数则直接使用

  45. // 在调用 getBean 方法的时候指定了方法参数

  46. if (explicitArgs != null) {

  47. argsToUse = explicitArgs;

  48. }

  49. else {

  50. // 没有指定,则尝试从配置文件中解析

  51. Object[] argsToResolve = null;

  52. // 首先尝试从缓存中获取

  53. synchronized (mbd.constructorArgumentLock) {

  54. // 获取缓存中的构造函数或者工厂方法

  55. factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;

  56. if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {

  57. // 获取缓存中的构造参数

  58. argsToUse = mbd.resolvedConstructorArguments;

  59. if (argsToUse == null) {

  60. // 获取缓存中的构造函数参数的包可见字段

  61. argsToResolve = mbd.preparedConstructorArguments;

  62. }

  63. }

  64. }

  65. // 缓存中存在,则解析存储在 BeanDefinition 中的参数

  66. // 如给定方法的构造函数 A(int ,int ),则通过此方法后就会把配置文件中的("1","1")转换为 (1,1)

  67. // 缓存中的值可能是原始值也有可能是最终值

  68. if (argsToResolve != null) {

  69. argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve);

  70. }

  71. }


  72. //

  73. if (factoryMethodToUse == null || argsToUse == null) {

  74. // 获取工厂方法的类全名称

  75. factoryClass = ClassUtils.getUserClass(factoryClass);


  76. // 获取所有待定方法

  77. Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);

  78. // 检索所有方法,这里是对方法进行过滤

  79. List<Method> candidateSet = new ArrayList<>();

  80. for (Method candidate : rawCandidates) {

  81. // 如果有static 且为工厂方法,则添加到 candidateSet 中

  82. if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {

  83. candidateSet.add(candidate);

  84. }

  85. }


  86. Method[] candidates = candidateSet.toArray(new Method[0]);

  87. // 排序构造函数

  88. // public 构造函数优先参数数量降序,非public 构造函数参数数量降序

  89. AutowireUtils.sortFactoryMethods(candidates);


  90. // 用于承载解析后的构造函数参数的值

  91. ConstructorArgumentValues resolvedValues = null;

  92. boolean autowiring = (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);

  93. int minTypeDiffWeight = Integer.MAX_VALUE;

  94. Set<Method> ambiguousFactoryMethods = null;


  95. int minNrOfArgs;

  96. if (explicitArgs != null) {

  97. minNrOfArgs = explicitArgs.length;

  98. }

  99. else {

  100. // getBean() 没有传递参数,则需要解析保存在 BeanDefinition 构造函数中指定的参数

  101. if (mbd.hasConstructorArgumentValues()) {

  102. // 构造函数的参数

  103. ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();

  104. resolvedValues = new ConstructorArgumentValues();

  105. // 解析构造函数的参数

  106. // 将该 bean 的构造函数参数解析为 resolvedValues 对象,其中会涉及到其他 bean

  107. minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);

  108. }

  109. else {

  110. minNrOfArgs = 0;

  111. }

  112. }


  113. LinkedList<UnsatisfiedDependencyException> causes = null;


  114. for (Method candidate : candidates) {

  115. // 方法体的参数

  116. Class<?>[] paramTypes = candidate.getParameterTypes();


  117. if (paramTypes.length >= minNrOfArgs) {

  118. // 保存参数的对象

  119. ArgumentsHolder argsHolder;


  120. // getBean()传递了参数

  121. if (explicitArgs != null){

  122. // 显示给定参数,参数长度必须完全匹配

  123. if (paramTypes.length != explicitArgs.length) {

  124. continue;

  125. }

  126. // 根据参数创建参数持有者

  127. argsHolder = new ArgumentsHolder(explicitArgs);

  128. }

  129. else {

  130. // 为提供参数,解析构造参数

  131. try {

  132. String[] paramNames = null;

  133. // 获取 ParameterNameDiscoverer 对象

  134. // ParameterNameDiscoverer 是用于解析方法和构造函数的参数名称的接口,为参数名称探测器

  135. ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();

  136. if (pnd != null) {

  137. // 获取指定构造函数的参数名称

  138. paramNames = pnd.getParameterNames(candidate);

  139. }



  140. // 在已经解析的构造函数参数值的情况下,创建一个参数持有者对象

  141. argsHolder = createArgumentArray(

  142. beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring);

  143. }

  144. catch (UnsatisfiedDependencyException ex) {

  145. if (this.beanFactory.logger.isTraceEnabled()) {

  146. this.beanFactory.logger.trace("Ignoring factory method [" + candidate +

  147. "] of bean '" + beanName + "': " + ex);

  148. }

  149. if (causes == null) {

  150. causes = new LinkedList<>();

  151. }

  152. causes.add(ex);

  153. continue;

  154. }

  155. }


  156. // isLenientConstructorResolution 判断解析构造函数的时候是否以宽松模式还是严格模式

  157. // 严格模式:解析构造函数时,必须所有的都需要匹配,否则抛出异常

  158. // 宽松模式:使用具有"最接近的模式"进行匹配

  159. // typeDiffWeight:类型差异权重

  160. int typeDiffWeight = (mbd.isLenientConstructorResolution() ?

  161. argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));

  162. // 代表最接近的类型匹配,则选择作为构造函数

  163. if (typeDiffWeight < minTypeDiffWeight) {

  164. factoryMethodToUse = candidate;

  165. argsHolderToUse = argsHolder;

  166. argsToUse = argsHolder.arguments;

  167. minTypeDiffWeight = typeDiffWeight;

  168. ambiguousFactoryMethods = null;

  169. }


  170. // 如果具有相同参数数量的方法具有相同的类型差异权重,则收集此类型选项

  171. // 但是,仅在非宽松构造函数解析模式下执行该检查,并显式忽略重写方法(具有相同的参数签名)

  172. else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&

  173. !mbd.isLenientConstructorResolution() &&

  174. paramTypes.length == factoryMethodToUse.getParameterCount() &&

  175. !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {


  176. // 查找到多个可匹配的方法

  177. if (ambiguousFactoryMethods == null) {

  178. ambiguousFactoryMethods = new LinkedHashSet<>();

  179. ambiguousFactoryMethods.add(factoryMethodToUse);

  180. }

  181. ambiguousFactoryMethods.add(candidate);

  182. }

  183. }

  184. }


  185. // 没有可执行的工厂方法,抛出异常

  186. if (factoryMethodToUse == null) {

  187. if (causes != null) {

  188. UnsatisfiedDependencyException ex = causes.removeLast();

  189. for (Exception cause : causes) {

  190. this.beanFactory.onSuppressedException(cause);

  191. }

  192. throw ex;

  193. }

  194. List<String> argTypes = new ArrayList<>(minNrOfArgs);

  195. if (explicitArgs != null) {

  196. for (Object arg : explicitArgs) {

  197. argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");

  198. }

  199. }

  200. else if (resolvedValues != null){

  201. Set<ConstructorArgumentValues.ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount());

  202. valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());

  203. valueHolders.addAll(resolvedValues.getGenericArgumentValues());

  204. for (ConstructorArgumentValues.ValueHolder value : valueHolders) {

  205. String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :

  206. (value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));

  207. argTypes.add(argType);

  208. }

  209. }

  210. String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);

  211. throw new BeanCreationException(mbd.getResourceDescription(), beanName,

  212. "No matching factory method found: " +

  213. (mbd.getFactoryBeanName() != null ?

  214. "factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +

  215. "factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +

  216. "Check that a method with the specified name " +

  217. (minNrOfArgs > 0 ? "and arguments " : "") +

  218. "exists and that it is " +

  219. (isStatic ? "static" : "non-static") + ".");

  220. }

  221. else if (void.class == factoryMethodToUse.getReturnType()) {

  222. throw new BeanCreationException(mbd.getResourceDescription(), beanName,

  223. "Invalid factory method '" + mbd.getFactoryMethodName() +

  224. "': needs to have a non-void return type!");

  225. }

  226. else if (ambiguousFactoryMethods != null) {

  227. throw new BeanCreationException(mbd.getResourceDescription(), beanName,

  228. "Ambiguous factory method matches found in bean '" + beanName + "' " +

  229. "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +

  230. ambiguousFactoryMethods);

  231. }


  232. if (explicitArgs == null && argsHolderToUse != null) {

  233. // 将解析的构造函数加入缓存

  234. argsHolderToUse.storeCache(mbd, factoryMethodToUse);

  235. }

  236. }


  237. try {

  238. // 实例化 bean

  239. Object beanInstance;


  240. if (System.getSecurityManager() != null) {

  241. final Object fb = factoryBean;

  242. final Method factoryMethod = factoryMethodToUse;

  243. final Object[] args = argsToUse;

  244. // 通过执行工厂方法来创建bean示例

  245. beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->

  246. beanFactory.getInstantiationStrategy().instantiate(mbd, beanName, beanFactory, fb, factoryMethod, args),

  247. beanFactory.getAccessControlContext());

  248. }

  249. else {

  250. // 通过执行工厂方法来创建bean示例

  251. beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(

  252. mbd, beanName, this.beanFactory, factoryBean, factoryMethodToUse, argsToUse);

  253. }


  254. // 包装为 BeanWraper 对象

  255. bw.setBeanInstance(beanInstance);

  256. return bw;

  257. }

  258. catch (Throwable ex) {

  259. throw new BeanCreationException(mbd.getResourceDescription(), beanName,

  260. "Bean instantiation via factory method failed", ex);

  261. }

  262. }

instantiateUsingFactoryMethod() 方法体实在是太大了,处理细节感觉很复杂,LZ是硬着头皮看完的,中间断断续续的。吐槽这里的代码风格,完全不符合我们前面看的 Spring 代码风格。Spring 的一贯做法是将一个复杂逻辑进行拆分,分为多个细小的模块进行嵌套,每个模块负责一部分功能,模块与模块之间层层嵌套,上一层一般都是对下一层的总结和概括,这样就会使得每一层的逻辑变得清晰易懂。

回归到上面的方法体,虽然代码体量大,但是总体我们还是可看清楚这个方法要做的事情。一句话概括就是:确定工厂对象,然后获取构造函数和构造参数,最后调用 InstantiationStrategy 对象的 instantiate() 来创建 bean 实例。下面我们就这个句概括的话进行拆分并详细说明。

确定工厂对象

首先获取工厂方法名,若工厂方法名不为空,则调用 beanFactory.getBean() 获取工厂对象,若为空,则可能为一个静态工厂,对于静态工厂则必须提供工厂类的全类名,同时设置 factoryBean=null

构造参数确认

工厂对象确定后,则是确认构造参数。构造参数的确认主要分为三种情况:explicitArgs 参数、缓存中获取、配置文件中解析。

explicitArgs 参数

explicitArgs 参数是我们调用 getBean() 时传递景来,一般该参数,该参数就是用于初始化 bean 时所传递的参数,如果该参数不为空,则可以确定构造函数的参数就是它了。

缓存中获取

在该方法的最后,我们会发现这样一段代码: argsHolderToUse.storeCache(mbd,factoryMethodToUse) ,这段代码主要是将构造函数、构造参数保存到缓存中,如下:


  1. public void storeCache(RootBeanDefinition mbd, Executable constructorOrFactoryMethod) {

  2. synchronized (mbd.constructorArgumentLock) {

  3. mbd.resolvedConstructorOrFactoryMethod = constructorOrFactoryMethod;

  4. mbd.constructorArgumentsResolved = true;

  5. if (this.resolveNecessary) {

  6. mbd.preparedConstructorArguments = this.preparedArguments;

  7. }

  8. else {

  9. mbd.resolvedConstructorArguments = this.arguments;

  10. }

  11. }

  12. }

其中涉及到的几个参数 constructorArgumentLock、resolvedConstructorOrFactoryMethod、constructorArgumentsResolved、resolvedConstructorArguments。这些参数都是跟构造函数、构造函数缓存有关的。

constructorArgumentLock:构造函数的缓存锁

resolvedConstructorOrFactoryMethod:缓存已经解析的构造函数或者工厂方法

constructorArgumentsResolved:标记字段,标记构造函数、参数已经解析了。默认为false

resolvedConstructorArguments:缓存已经解析的构造函数参数,包可见字段

所以从缓存中获取就是提取这几个参数的值,如下:


  1. synchronized (mbd.constructorArgumentLock) {

  2. // 获取缓存中的构造函数或者工厂方法

  3. factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;

  4. if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {

  5. // 获取缓存中的构造参数

  6. argsToUse = mbd.resolvedConstructorArguments;

  7. if (argsToUse == null) {

  8. // 获取缓存中的构造函数参数的包可见字段

  9. argsToResolve = mbd.preparedConstructorArguments;

  10. }

  11. }

  12. }

如果缓存中存在构造参数,则需要调用 resolvePreparedArguments() 方法进行转换,因为缓存中的值有可能是最终值也有可能不是最终值,比如我们构造函数中的类型为 Integer 类型的 1 ,但是原始的参数类型有可能是 String 类型的 1 ,所以即便是从缓存中得到了构造参数也需要经过一番的类型转换确保参数类型完全对应。

配置文件中解析

即没有通过传递参数的方式传递构造参数,缓存中也没有,那就只能通过解析配置文件获取构造参数了。

在 bean 解析类的博文中我们了解了,配置文件中的信息都会转换到 BeanDefinition 实例对象中,所以配置文件中的参数可以直接通过 BeanDefinition 对象获取。代码如下:


  1. if (mbd.hasConstructorArgumentValues()) {

  2. // 构造函数的参数

  3. ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();

  4. resolvedValues = new ConstructorArgumentValues();

  5. // 解析构造函数的参数

  6. // 将该 bean 的构造函数参数解析为 resolvedValues 对象,其中会涉及到其他 bean

  7. minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);

  8. }

通过 BeanDefinition 的 getConstructorArgumentValues() 就可以获取构造信息了,有了构造信息就可以获取相关的参数值信息了,获取的参数信息包括直接值和引用,这一步骤的处理交由 resolveConstructorArguments()完成,该方法会将构造参数信息解析为 resolvedValues 对象 并返回解析到的参数个数。

构造函数

确定构造参数后,下一步则是确定构造函数。第一步则是通过 getCandidateMethods() 获取所有的构造方法,同时对构造方法进行刷选,然后在对其进行排序处理( AutowireUtils.sortFactoryMethods(candidates)),排序的主要目的是为了能够更加方便的找到匹配的构造函数,因为构造函数的确认是根据参数个数确认的。排序的规则是:public 构造函数优先参数数量降序、非 public 构造参数数量降序。

通过迭代 candidates(包含了所有要匹配的构造函数)的方式,一次比较其参数,如果显示提供了参数(explicitArgs != null),则直接比较两者是否相等,如果相等则表示找到了,否则继续比较。如果没有显示提供参数,则需要获取 ParameterNameDiscoverer 对象,该对象为参数名称探测器,主要用于发现方法和构造函数的参数名称。

将参数包装成 ArgumentsHolder 对象,该对象用于保存参数,我们称之为参数持有者。当将对象包装成 ArgumentsHolder 对象后,我们就可以通过它来进行构造函数匹配,匹配分为严格模式和宽松模式。

严格模式:解析构造函数时,必须所有参数都需要匹配,否则抛出异常

宽松模式:使用具有"最接近的模式"进行匹配

判断的依据是根据 BeanDefinition 的 isLenientConstructorResolution 属性(该参数是我们在构造 AbstractBeanDefinition 对象是传递的)来获取类型差异权重(typeDiffWeight) 的。如果 typeDiffWeight<minTypeDiffWeight ,则代表“最接近的模式”,选择其作为构造函数,否则只有两者具有相同的参数数量且类型差异权重相等才会纳入考虑范围。

至此,构造函数已经确认了。

创建 bean 实例

工厂对象、构造函数、构造参数都已经确认了,则最后一步就是调用 InstantiationStrategy 对象的 instantiate() 来创建 bean 实例,如下:


  1. public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,

  2. @Nullable Object factoryBean, final Method factoryMethod, @Nullable Object... args) {


  3. try {

  4. if (System.getSecurityManager() != null) {

  5. AccessController.doPrivileged((PrivilegedAction<Object>) () -> {

  6. ReflectionUtils.makeAccessible(factoryMethod);

  7. return null;

  8. });

  9. }

  10. else {

  11. ReflectionUtils.makeAccessible(factoryMethod);

  12. }


  13. Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();

  14. try {

  15. currentlyInvokedFactoryMethod.set(factoryMethod);

  16. // 执行工厂方法,并返回实例

  17. Object result = factoryMethod.invoke(factoryBean, args);

  18. if (result == null) {

  19. result = new NullBean();

  20. }

  21. return result;

  22. }

  23. finally {

  24. if (priorInvokedFactoryMethod != null) {

  25. currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);

  26. }

  27. else {

  28. currentlyInvokedFactoryMethod.remove();

  29. }

  30. }

  31. }

  32. // 省略一波 catch

  33. }

instantiate() 最核心的部分就是利用 Java 反射执行工厂方法并返回创建好的实例,也就是这段代码:


  1. Object result = factoryMethod.invoke(factoryBean, args);

到这里 instantiateUsingFactoryMethod() 已经分析完毕了,这里 LZ 有些题外话需要说下,看源码真心是一个痛苦的过程,尤其是复杂的源码,比如这个方法我看了三天才弄清楚点皮毛,当然这里跟 LZ 的智商有些关系(智商捉急 ┭┮﹏┭┮),写这篇博客也花了五天时间才写完(最后截稿日为:2018.08.10 01:23:49),所以每一个坚持写博客的都是折翼的天使,值得各位尊敬

createBeanInstance() 还有两个重要方法 autowireConstructor()instantiateBean() ,由于篇幅问题,所以将这两个方法放在下篇博客分析。敬请期待!!!


原文发布时间为:2018-10-31
本文作者:Java技术驿站
本文来自云栖社区合作伙伴“Java技术驿站”,了解相关信息可以关注“Java技术驿站”。