【死磕 Spring】—– IOC 之构造函数实例化 bean

简介:
createBeanInstance() 用于实例化 bean,它会根据不同情况选择不同的实例化策略来完成 bean 的初始化,主要包括:
  • Supplier 回调: obtainFromSupplier()

  • 工厂方法初始化: instantiateUsingFactoryMethod()

  • 构造函数自动注入初始化: autowireConstructor()

  • 默认构造函数注入: instantiateBean()

在上篇博客(【死磕 Spring】----- IOC 之 Factory 实例化 bean) 中分析了 Supplier 回调和工厂方法初始化,这篇分析两个构造函数注入。

autowireConstructor()

这个初始化方法我们可以简单理解为是带有参数的初始化 bean 。代码段如下:

 
  1. public BeanWrapper autowireConstructor(final String beanName, final RootBeanDefinition mbd,

  2. @Nullable Constructor<?>[] chosenCtors, @Nullable final Object[] explicitArgs) {

  3. // 封装 BeanWrapperImpl 并完成初始化

  4. BeanWrapperImpl bw = new BeanWrapperImpl();

  5. this.beanFactory.initBeanWrapper(bw);


  6. // 构造函数

  7. Constructor<?> constructorToUse = null;

  8. // 构造参数

  9. ArgumentsHolder argsHolderToUse = null;

  10. Object[] argsToUse = null;


  11. /*

  12. * 确定构造参数

  13. */

  14. // 如果 getBean() 已经传递,则直接使用

  15. if (explicitArgs != null) {

  16. argsToUse = explicitArgs;

  17. }

  18. else {


  19. /*

  20. * 尝试从缓存中获取

  21. */

  22. Object[] argsToResolve = null;

  23. synchronized (mbd.constructorArgumentLock) {

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

  25. constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;

  26. if (constructorToUse != null && mbd.constructorArgumentsResolved) {

  27. // 缓存中的构造参数

  28. argsToUse = mbd.resolvedConstructorArguments;

  29. if (argsToUse == null) {

  30. argsToResolve = mbd.preparedConstructorArguments;

  31. }

  32. }

  33. }


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

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

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

  37. if (argsToResolve != null) {

  38. argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);

  39. }

  40. }


  41. /*

  42. * 没有缓存,则尝试从配置文件中获取

  43. */

  44. if (constructorToUse == null) {

  45. // 是否需要解析构造器

  46. boolean autowiring = (chosenCtors != null ||

  47. mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);


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

  49. ConstructorArgumentValues resolvedValues = null;


  50. int minNrOfArgs;

  51. if (explicitArgs != null) {

  52. minNrOfArgs = explicitArgs.length;

  53. }

  54. else {

  55. // 从 BeanDefinition 中获取构造参数,也就是从配置文件中提取构造参数

  56. ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();


  57. resolvedValues = new ConstructorArgumentValues();

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

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

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

  61. }


  62. /*

  63. * 获取指定的构造函数

  64. */

  65. // 根据前面的判断,chosenCtors 应该为 null

  66. Constructor<?>[] candidates = chosenCtors;

  67. if (candidates == null) {

  68. // 获取 bean 的 class

  69. Class<?> beanClass = mbd.getBeanClass();

  70. try {

  71. // 根据 class 获取所有的构造函数

  72. candidates = (mbd.isNonPublicAccessAllowed() ?

  73. beanClass.getDeclaredConstructors() : beanClass.getConstructors());

  74. }

  75. catch (Throwable ex) {

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

  77. "Resolution of declared constructors on bean Class [" + beanClass.getName() +

  78. "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);

  79. }

  80. }


  81. // 对构造函数进行排序处理

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

  83. AutowireUtils.sortConstructors(candidates);


  84. // 最小参数类型权重

  85. int minTypeDiffWeight = Integer.MAX_VALUE;

  86. Set<Constructor<?>> ambiguousConstructors = null;

  87. LinkedList<UnsatisfiedDependencyException> causes = null;


  88. // 迭代所有构造函数

  89. for (Constructor<?> candidate : candidates) {

  90. // 获取该构造函数的参数类型

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


  92. // 如果已经找到选用的构造函数或者需要的参数个数小于当前的构造函数参数个数,则终止

  93. // 因为已经按照参数个数降序排列了

  94. if (constructorToUse != null && argsToUse.length > paramTypes.length) {

  95. break;

  96. }

  97. // 参数个数不等,继续

  98. if (paramTypes.length < minNrOfArgs) {

  99. continue;

  100. }


  101. // 参数持有者

  102. ArgumentsHolder argsHolder;

  103. // 有参数

  104. if (resolvedValues != null) {

  105. try {

  106. // 注释上获取参数名称

  107. String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);

  108. if (paramNames == null) {

  109. // 获取构造函数、方法参数的探测器

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

  111. if (pnd != null) {

  112. // 通过探测器获取构造函数的参数名称

  113. paramNames = pnd.getParameterNames(candidate);

  114. }

  115. }


  116. // 根据构造函数和构造参数创建参数持有者

  117. argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,

  118. getUserDeclaredConstructor(candidate), autowiring);

  119. }

  120. catch (UnsatisfiedDependencyException ex) {

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

  122. this.beanFactory.logger.trace(

  123. "Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);

  124. }

  125. // Swallow and try next constructor.

  126. if (causes == null) {

  127. causes = new LinkedList<>();

  128. }

  129. causes.add(ex);

  130. continue;

  131. }

  132. }

  133. else {

  134. // 构造函数没有参数

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

  136. continue;

  137. }

  138. argsHolder = new ArgumentsHolder(explicitArgs);

  139. }


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

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

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

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

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

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


  146. // 如果它代表着当前最接近的匹配则选择其作为构造函数

  147. if (typeDiffWeight < minTypeDiffWeight) {

  148. constructorToUse = candidate;

  149. argsHolderToUse = argsHolder;

  150. argsToUse = argsHolder.arguments;

  151. minTypeDiffWeight = typeDiffWeight;

  152. ambiguousConstructors = null;

  153. }

  154. else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {

  155. if (ambiguousConstructors == null) {

  156. ambiguousConstructors = new LinkedHashSet<>();

  157. ambiguousConstructors.add(constructorToUse);

  158. }

  159. ambiguousConstructors.add(candidate);

  160. }

  161. }


  162. if (constructorToUse == null) {

  163. if (causes != null) {

  164. UnsatisfiedDependencyException ex = causes.removeLast();

  165. for (Exception cause : causes) {

  166. this.beanFactory.onSuppressedException(cause);

  167. }

  168. throw ex;

  169. }

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

  171. "Could not resolve matching constructor " +

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

  173. }

  174. else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {

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

  176. "Ambiguous constructor matches found in bean '" + beanName + "' " +

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

  178. ambiguousConstructors);

  179. }


  180. // 将构造函数、构造参数保存到缓存中

  181. if (explicitArgs == null) {

  182. argsHolderToUse.storeCache(mbd, constructorToUse);

  183. }

  184. }


  185. try {

  186. // 获取创建 bean 的策略

  187. final InstantiationStrategy strategy = beanFactory.getInstantiationStrategy();

  188. Object beanInstance;


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

  190. final Constructor<?> ctorToUse = constructorToUse;

  191. final Object[] argumentsToUse = argsToUse;

  192. // 实例化 bean

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

  194. strategy.instantiate(mbd, beanName, beanFactory, ctorToUse, argumentsToUse),

  195. beanFactory.getAccessControlContext());

  196. }

  197. else {

  198. // 实例化bean

  199. beanInstance = strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse);

  200. }


  201. // 将构造的 bean 加入到 BeanWrapper 实例中

  202. bw.setBeanInstance(beanInstance);

  203. return bw;

  204. }

  205. catch (Throwable ex) {

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

  207. "Bean instantiation via constructor failed", ex);

  208. }

  209. }

代码与 instantiateUsingFactoryMethod() 一样,又长又难懂,但是如果理解了 instantiateUsingFactoryMethod() 初始化 bean 的过程,那么 autowireConstructor() 也不存在什么难的地方了,一句话概括:首先确定构造函数参数、构造函数,然后调用相应的初始化策略进行 bean 的初始化。关于如何确定构造函数、构造参数,该部分逻辑和 instantiateUsingFactoryMethod() 基本一致,所以这里不再重复阐述了,具体过程请移步【死磕 Spring】----- IOC 之 Factory 实例化 bean,这里我们重点分析初始化策略。

对于初始化策略,首先是获取实例化 bean 的策略,如下:

 
  1. final InstantiationStrategy strategy = beanFactory.getInstantiationStrategy();

然后是调用其 instantiate()方法,该方法在 SimpleInstantiationStrategy 中实现,如下:

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

  2. // 没有覆盖

  3. // 直接使用反射实例化即可

  4. if (!bd.hasMethodOverrides()) {

  5. // 重新检测获取下构造函数

  6. // 该构造函数是经过前面 N 多复杂过程确认的构造函数

  7. Constructor<?> constructorToUse;

  8. synchronized (bd.constructorArgumentLock) {

  9. // 获取已经解析的构造函数

  10. constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;

  11. // 如果为 null,从 class 中解析获取,并设置

  12. if (constructorToUse == null) {

  13. final Class<?> clazz = bd.getBeanClass();

  14. if (clazz.isInterface()) {

  15. throw new BeanInstantiationException(clazz, "Specified class is an interface");

  16. }

  17. try {

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

  19. constructorToUse = AccessController.doPrivileged(

  20. (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);

  21. }

  22. else {

  23. constructorToUse = clazz.getDeclaredConstructor();

  24. }

  25. bd.resolvedConstructorOrFactoryMethod = constructorToUse;

  26. }

  27. catch (Throwable ex) {

  28. throw new BeanInstantiationException(clazz, "No default constructor found", ex);

  29. }

  30. }

  31. }


  32. // 通过BeanUtils直接使用构造器对象实例化bean

  33. return BeanUtils.instantiateClass(constructorToUse);

  34. }

  35. else {

  36. // 生成CGLIB创建的子类对象

  37. return instantiateWithMethodInjection(bd, beanName, owner);

  38. }

  39. }

如果该 bean 没有配置 lookup-method、replaced-method 标签或者 @Lookup 注解,则直接通过反射的方式实例化 bean 即可,方便快捷,但是如果存在需要覆盖的方法或者动态替换的方法则需要使用 CGLIB 进行动态代理,因为可以在创建代理的同时将动态方法织入类中。

反射

调用工具类 BeanUtils 的 instantiateClass() 方法完成反射工作:

 
  1. public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {

  2. Assert.notNull(ctor, "Constructor must not be null");

  3. try {

  4. ReflectionUtils.makeAccessible(ctor);

  5. return (KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?

  6. KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));

  7. }

  8. // 省略一些 catch

  9. }

CGLIB

 
  1. protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {

  2. throw new UnsupportedOperationException("Method Injection not supported in SimpleInstantiationStrategy");

  3. }

方法默认是没有实现的,具体过程由其子类 CglibSubclassingInstantiationStrategy 实现:

 
  1. protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {

  2. return instantiateWithMethodInjection(bd, beanName, owner, null);

  3. }


  4. protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,

  5. @Nullable Constructor<?> ctor, @Nullable Object... args) {


  6. // 通过CGLIB生成一个子类对象

  7. return new CglibSubclassCreator(bd, owner).instantiate(ctor, args);

  8. }

创建一个 CglibSubclassCreator 对象,调用其 instantiate() 方法生成其子类对象:

 
  1. public Object instantiate(@Nullable Constructor<?> ctor, @Nullable Object... args) {

  2. // 通过 Cglib 创建一个代理类

  3. Class<?> subclass = createEnhancedSubclass(this.beanDefinition);

  4. Object instance;

  5. // 没有构造器,通过 BeanUtils 使用默认构造器创建一个bean实例

  6. if (ctor == null) {

  7. instance = BeanUtils.instantiateClass(subclass);

  8. }

  9. else {

  10. try {

  11. // 获取代理类对应的构造器对象,并实例化 bean

  12. Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());

  13. instance = enhancedSubclassConstructor.newInstance(args);

  14. }

  15. catch (Exception ex) {

  16. throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),

  17. "Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);

  18. }

  19. }


  20. // 为了避免memory leaks异常,直接在bean实例上设置回调对象

  21. Factory factory = (Factory) instance;

  22. factory.setCallbacks(new Callback[] {NoOp.INSTANCE,

  23. new CglibSubclassingInstantiationStrategy.LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),

  24. new CglibSubclassingInstantiationStrategy.ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});

  25. return instance;

  26. }

到这类 CGLIB 的方式分析完毕了,当然这里还没有具体分析 CGLIB 生成子类的详细过程,具体的过程等后续分析 AOP 的时候再详细地介绍。instantiateBean()

 
  1. protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {

  2. try {

  3. Object beanInstance;

  4. final BeanFactory parent = this;

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

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

  7. getInstantiationStrategy().instantiate(mbd, beanName, parent),

  8. getAccessControlContext());

  9. }

  10. else {

  11. beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);

  12. }

  13. BeanWrapper bw = new BeanWrapperImpl(beanInstance);

  14. initBeanWrapper(bw);

  15. return bw;

  16. }

  17. catch (Throwable ex) {

  18. throw new BeanCreationException(

  19. mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);

  20. }

  21. }

这个方法相比于 instantiateUsingFactoryMethod()autowireConstructor() 方法实在是太简单了,因为它没有参数,所以不需要确认经过复杂的过来来确定构造器、构造参数,所以这里就不过多阐述了。

对于 createBeanInstance() 而言,他就是选择合适实例化策略来为 bean 创建实例对象,具体的策略有:Supplier 回调方式、工厂方法初始化、构造函数自动注入初始化、默认构造函数注入。其中工厂方法初始化和构造函数自动注入初始化两种方式最为复杂,主要是因为构造函数和构造参数的不确定性,Spring 需要花大量的精力来确定构造函数和构造参数,如果确定了则好办,直接选择实例化策略即可。当然在实例化的时候会根据是否有需要覆盖或者动态替换掉的方法,因为存在覆盖或者织入的话需要创建动态代理将方法织入,这个时候就只能选择 CGLIB 的方式来实例化,否则直接利用反射的方式即可,方便快捷。

到这里 createBeanInstance() 的过程就已经分析完毕了,下篇介绍 doCreateBean() 方法中的第二个过程:属性填充。


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

相关文章
|
24天前
|
缓存 Java Spring
Spring 框架中 Bean 的生命周期
Spring 框架中 Bean 的生命周期
32 1
|
1月前
|
XML Java 开发者
Spring Boot中的bean注入方式和原理
Spring Boot中的bean注入方式和原理
59 0
|
23小时前
|
XML 人工智能 Java
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
|
9天前
|
Java 数据库连接 开发者
浅谈Spring的Bean生命周期
浅谈Spring的Bean生命周期
17 1
|
13天前
|
XML Java 数据格式
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
19 0
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
|
22天前
|
XML Java 数据格式
Spring(一)IOC小案例
Spring(一)IOC小案例
|
24天前
|
XML Java 程序员
作为Java程序员还不知道Spring中Bean创建过程和作用?
作为Java程序员还不知道Spring中Bean创建过程和作用?
14 0
|
28天前
|
XML 缓存 Java
天天用 Spring,bean 实例化原理你懂吗
天天用 Spring,bean 实例化原理你懂吗
17 0
|
1月前
|
Java Spring
Spring5深入浅出篇:bean的生命周期
Spring5深入浅出篇:bean的生命周期
|
1月前
|
XML Java 数据格式
Spring 的奇幻起源:从 IoC 容器到 Bean 的魔法世界 (下)
Spring 的奇幻起源:从 IoC 容器到 Bean 的魔法世界