【死磕 Spring】—– IOC 之开启 bean 的实例化进程

简介:
在上篇博客 【死磕 Spring】----- 加载 bean 之 分析各 scope 的 bean 创建中有一个核心方法没有讲到 createBean() ,该方法的如下:
 
  1. protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

  2. throws BeanCreationException;

该方法定义在 AbstractBeanFactory 中。其含义是根据给定的 BeanDefinition 和 args实例化一个 bean 对象,如果该 BeanDefinition 存在父类,则该 BeanDefinition 已经合并了父类的属性。所有 Bean 实例的创建都会委托给该方法实现。

方法接受三个参数:

beanName:bean 的名字

mbd:已经合并了父类属性的(如果有的话)BeanDefinition

args:用于构造函数或者工厂方法创建 bean 实例对象的参数

该抽象方法的默认实现是在类 AbstractAutowireCapableBeanFactory 中实现,如下:

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

  2. throws BeanCreationException {


  3. if (logger.isDebugEnabled()) {

  4. logger.debug("Creating instance of bean '" + beanName + "'");

  5. }

  6. RootBeanDefinition mbdToUse = mbd;


  7. // 确保此时的 bean 已经被解析了

  8. // 如果获取的class 属性不为null,则克隆该 BeanDefinition

  9. // 主要是因为该动态解析的 class 无法保存到到共享的 BeanDefinition

  10. Class<?> resolvedClass = resolveBeanClass(mbd, beanName);

  11. if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {

  12. mbdToUse = new RootBeanDefinition(mbd);

  13. mbdToUse.setBeanClass(resolvedClass);

  14. }


  15. try {

  16. // 验证和准备覆盖方法

  17. mbdToUse.prepareMethodOverrides();

  18. }

  19. catch (BeanDefinitionValidationException ex) {

  20. throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),

  21. beanName, "Validation of method overrides failed", ex);

  22. }


  23. try {

  24. // 给 BeanPostProcessors 一个机会用来返回一个代理类而不是真正的类实例

  25. // AOP 的功能就是基于这个地方

  26. Object bean = resolveBeforeInstantiation(beanName, mbdToUse);

  27. if (bean != null) {

  28. return bean;

  29. }

  30. }

  31. catch (Throwable ex) {

  32. throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,

  33. "BeanPostProcessor before instantiation of bean failed", ex);

  34. }


  35. try {

  36. // 执行真正创建 bean 的过程

  37. Object beanInstance = doCreateBean(beanName, mbdToUse, args);

  38. if (logger.isDebugEnabled()) {

  39. logger.debug("Finished creating instance of bean '" + beanName + "'");

  40. }

  41. return beanInstance;

  42. }

  43. catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {

  44. throw ex;

  45. }

  46. catch (Throwable ex) {

  47. throw new BeanCreationException(

  48. mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);

  49. }

  50. }

过程如下:

解析指定 BeanDefinition 的 class

处理 override 属性

实例化的前置处理

创建 bean

解析指定 BeanDefinition 的 class

 
  1. Class<?> resolvedClass = resolveBeanClass(mbd, beanName)

这个方法主要是解析 bean definition 的 class 类,并将已经解析的 Class 存储在 bean definition 中以供后面使用。如果解析的 class 不为空,则会将该 BeanDefinition 进行克隆至 mbdToUse,这样做的主要目的是以为动态解析的 class 是无法保存到共享的 BeanDefinition 中。

处理 override 属性

大家还记得 lookup-method 和 replace-method 这两个配置功能?在博客 【死磕 Spring】----- IOC 之解析Bean:解析 bean 标签(三) 中已经详细分析了这两个标签的用法和解析过程,知道解析过程其实就是讲这两个配置存放在 BeanDefinition 中的 methodOverrides 属性中,我们知道在 bean 实例化的过程中如果检测到存在 methodOverrides,则会动态地位为当前 bean 生成代理并使用对应的拦截器为 bean 做增强处理。具体的实现我们后续分析,现在先看 mbdToUse.prepareMethodOverrides() 都干了些什么事,如下:

 
  1. public void prepareMethodOverrides() throws BeanDefinitionValidationException {

  2. if (hasMethodOverrides()) {

  3. Set<MethodOverride> overrides = getMethodOverrides().getOverrides();

  4. synchronized (overrides) {

  5. for (MethodOverride mo : overrides) {

  6. prepareMethodOverride(mo);

  7. }

  8. }

  9. }

  10. }

如果存在 methodOverrides 则获取所有的 override method ,然后通过迭代的方法一次调用 prepareMethodOverride() ,如下:

 
  1. protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {

  2. int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());

  3. if (count == 0) {

  4. throw new BeanDefinitionValidationException(

  5. "Invalid method override: no method with name '" + mo.getMethodName() +

  6. "' on class [" + getBeanClassName() + "]");

  7. }

  8. else if (count == 1) {

  9. mo.setOverloaded(false);

  10. }

  11. }

根据方法名称从 class 中获取该方法名的个数,如果为 0 则抛出异常,如果 为 1 则设置该重载方法没有被重载。若一个类中存在多个重载方法,则在方法调用的时候还需要根据参数类型来判断到底重载的是哪个方法。在设置重载的时候其实这里做了一个小小优化,那就是当 count==1 时,设置 overloaded=false,这样表示该方法没有重载,这样在后续调用的时候便可以直接找到方法而不需要进行方法参数的校验。

诚然,其实 mbdToUse.prepareMethodOverrides() 并没有做什么实质性的工作,只是对 methodOverrides 属性做了一些简单的校验而已。

实例化的前置处理

resolveBeforeInstantiation() 的作用是给 BeanPostProcessors 后置处理器返回一个代理对象的机会,其实在调用该方法之前 Spring 一直都没有创建 bean ,那么这里返回一个 bean 的代理类有什么作用呢?作用体现在后面的 if 判断:

 
  1. if (bean != null) {

  2. return bean;

  3. }

如果代理对象不为空,则直接返回代理对象,这一步骤有非常重要的作用,Spring 后续实现 AOP 就是基于这个地方判断的。

 
  1. protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {

  2. Object bean = null;

  3. if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {

  4. if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {

  5. Class<?> targetType = determineTargetType(beanName, mbd);

  6. if (targetType != null) {

  7. bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);

  8. if (bean != null) {

  9. bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);

  10. }

  11. }

  12. }

  13. mbd.beforeInstantiationResolved = (bean != null);

  14. }

  15. return bean;

  16. }

这个方法核心就在于 applyBeanPostProcessorsBeforeInstantiation()applyBeanPostProcessorsAfterInitialization() 两个方法,before 为实例化前的后处理器应用,after 为实例化后的后处理器应用,由于本文的主题是创建 bean,关于 Bean 的增强处理后续 LZ 会单独出博文来做详细说明。

创建 bean

如果没有代理对象,就只能走常规的路线进行 bean 的创建了,该过程有 doCreateBean() 实现,如下:

 
  1. protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)

  2. throws BeanCreationException {


  3. // BeanWrapper是对Bean的包装,其接口中所定义的功能很简单包括设置获取被包装的对象,获取被包装bean的属性描述器

  4. BeanWrapper instanceWrapper = null;

  5. // 单例模型,则从未完成的 FactoryBean 缓存中删除

  6. if (mbd.isSingleton()) {anceWrapper = this.factoryBeanInstanceCache.remove(beanName);

  7. }


  8. // 使用合适的实例化策略来创建新的实例:工厂方法、构造函数自动注入、简单初始化

  9. if (instanceWrapper == null) {

  10. instanceWrapper = createBeanInstance(beanName, mbd, args);

  11. }


  12. // 包装的实例对象

  13. final Object bean = instanceWrapper.getWrappedInstance();

  14. // 包装的实例对象的类型

  15. Class<?> beanType = instanceWrapper.getWrappedClass();

  16. if (beanType != NullBean.class) {

  17. mbd.resolvedTargetType = beanType;

  18. }


  19. // 检测是否有后置处理

  20. // 如果有后置处理,则允许后置处理修改 BeanDefinition

  21. synchronized (mbd.postProcessingLock) {

  22. if (!mbd.postProcessed) {

  23. try {

  24. // applyMergedBeanDefinitionPostProcessors

  25. // 后置处理修改 BeanDefinition

  26. applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);

  27. }

  28. catch (Throwable ex) {

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

  30. "Post-processing of merged bean definition failed", ex);

  31. }

  32. mbd.postProcessed = true;

  33. }

  34. }


  35. // 解决单例模式的循环依赖

  36. // 单例模式 & 运行循环依赖&当前单例 bean 是否正在被创建

  37. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&

  38. isSingletonCurrentlyInCreation(beanName));

  39. if (earlySingletonExposure) {

  40. if (logger.isDebugEnabled()) {

  41. logger.debug("Eagerly caching bean '" + beanName +

  42. "' to allow for resolving potential circular references");

  43. }

  44. // 提前将创建的 bean 实例加入到ectFactory 中

  45. // 这里是为了后期避免循环依赖

  46. addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

  47. }


  48. /*

  49. * 开始初始化 bean 实例对象

  50. */

  51. Object exposedObject = bean;

  52. try {

  53. // 对 bean 进行填充,将各个属性值注入,其中,可能存在依赖于其他 bean 的属性

  54. // 则会递归初始依赖 bean

  55. populateBean(beanName, mbd, instanceWrapper);

  56. // 调用初始化方法

  57. exposedObject = initializeBean(beanName, exposedObject, mbd);

  58. }

  59. catch (Throwable ex) {

  60. if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {

  61. throw (BeanCreationException) ex;

  62. }

  63. else {

  64. throw new BeanCreationException(

  65. mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);

  66. }

  67. }


  68. /**

  69. * 循环依赖处理

  70. */

  71. if (earlySingletonExposure) {

  72. // 获取 earlySingletonReference

  73. Object earlySingletonReference = getSingleton(beanName, false);

  74. // 只有在存在循环依赖的情况下,earlySingletonReference 才不会为空

  75. if (earlySingletonReference != null) {

  76. // 如果 exposedObject 没有在初始化方法中被改变,也就是没有被增强

  77. if (exposedObject == bean) {

  78. exposedObject = earlySingletonReference;

  79. }

  80. // 处理依赖

  81. else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {

  82. String[] dependentBeans = getDependentBeans(beanName);

  83. Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);

  84. for (String dependentBean : dependentBeans) {

  85. if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {

  86. actualDependentBeans.add(dependentBean);

  87. }

  88. }

  89. if (!actualDependentBeans.isEmpty()) {

  90. throw new BeanCurrentlyInCreationException(beanName,

  91. "Bean with name '" + beanName + "' has been injected into other beans [" +

  92. StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +

  93. "] in its raw version as part of a circular reference, but has eventually been " +

  94. "wrapped. This means that said other beans do not use the final version of the " +

  95. "bean. This is often the result of over-eager type matching - consider using " +

  96. "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");

  97. }

  98. }

  99. }

  100. }

  101. try {

  102. // 注册 bean

  103. registerDisposableBeanIfNecessary(beanName, bean, mbd);

  104. }

  105. catch (BeanDefinitionValidationException ex) {

  106. throw new BeanCreationException(

  107. mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);

  108. }


  109. return exposedObject;

  110. }

整体的思路:

  1. 如果是单例模式,则清除 factoryBeanInstanceCache 缓存,同时返回 BeanWrapper 实例对象,当然如果存在。

  2. 如果缓存中没有 BeanWrapper 或者不是单例模式,则调用 createBeanInstance() 实例化 bean,主要是将 BeanDefinition 转换为 BeanWrapper

  • MergedBeanDefinitionPostProcessor 的应用

  • 单例模式的循环依赖处理

  • 调用 populateBean() 进行属性填充。将所有属性填充至 bean 的实例中

  • 调用 initializeBean() 初始化 bean

  • 依赖检查

  • 注册 DisposableBean

doCreateBean() 完成 bean 的创建和初始化工作,内容太多,这里就只列出整体思路,下文开始将该方法进行拆分进行详细讲解,分布从以下几个方面进行阐述:

createBeanInstance() 实例化 bean

populateBean() 属性填充

循环依赖的处理

initializeBean() 初始化 bean


原文发布时间为:2018-10-31
本文作者:Java技术驿站
本文来自云栖社区合作伙伴“ Java技术驿站”,了解相关信息可以关注“ Java技术驿站”。
相关文章
|
18天前
|
缓存 Java Spring
Spring 框架中 Bean 的生命周期
Spring 框架中 Bean 的生命周期
30 1
|
1月前
|
XML Java 开发者
Spring Boot中的bean注入方式和原理
Spring Boot中的bean注入方式和原理
44 0
|
1月前
|
XML 缓存 Java
Spring源码之 Bean 的循环依赖
循环依赖是 Spring 中经典问题之一,那么到底什么是循环依赖?简单说就是对象之间相互引用, 如下图所示: 代码层面上很好理解,在 bean 创建过程中 class A 和 class B 又经历了怎样的过程呢? 可以看出形成了一个闭环,如果想解决这个问题,那么在属性填充时要保证不二次创建 A对象 的步骤,也就是必须保证从容器中能够直接获取到 B。 一、复现循环依赖问题 Spring 中默认允许循环依赖的存在,但在 Spring Boot 2.6.x 版本开始默认禁用了循环依赖 1. 基于xml复现循环依赖 定义实体 Bean java复制代码public class A {
|
2天前
|
Java 数据库连接 开发者
浅谈Spring的Bean生命周期
浅谈Spring的Bean生命周期
10 1
|
7天前
|
XML Java 数据格式
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
17 0
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
|
16天前
|
XML Java 数据格式
Spring(一)IOC小案例
Spring(一)IOC小案例
|
17天前
|
XML Java 程序员
作为Java程序员还不知道Spring中Bean创建过程和作用?
作为Java程序员还不知道Spring中Bean创建过程和作用?
12 0
|
22天前
|
XML 缓存 Java
天天用 Spring,bean 实例化原理你懂吗
天天用 Spring,bean 实例化原理你懂吗
17 0
|
1月前
|
Java Spring
Spring5深入浅出篇:bean的生命周期
Spring5深入浅出篇:bean的生命周期
|
1月前
|
XML Java 数据格式
Spring 的奇幻起源:从 IoC 容器到 Bean 的魔法世界 (下)
Spring 的奇幻起源:从 IoC 容器到 Bean 的魔法世界