Spring Bean创建和循环依赖

作者:? 时间:2023-10-21 09:17:51 

1 前言

前文已经讲述了Spring BeanFactory 与 FactoryBean 的区别详情,在本文中将继续讲解 Bean 的创建和初始化,在这个环节中将会涉及到 Bean 的创建、初始化和循环依赖内容。

2 Bean 的创建

在前文中已经讲述了 Spring 容器启动的核心方法 refresh,关于 Bean 的创建和初始化方法都是在 finishBeanFactoryInitialization() 中进行处理,在这个阶段就是处理所有剩余的非懒加载的单例对象。

Spring Bean创建和循环依赖

在该方法中,调用 preInstantiateSingletons() 进行 Bean 的所有单实例 bean。 在这个过程中,会获取容器中的所有 Bean, 依次进行初始化和创建对象。获取所有的 Bean 定义信息 beanDefinitionNames。在处理 Bean 时需要判断 Bean 定义信息是不是抽象的,单例,和懒加载。其核心方法为 getBean , 也许大家都知道在获取 Bean 的过程中,会经历 getBean -> doGetBean -> createBean -> doCreateBean 方法调用链,在 Spring 源码中, doXXX 的方法都是实际业务的方法,在 doCreateBean 方法中,createBeanInstance 方法是真实创建 Bean 对象的方法,在 Spring 中,都是采用反射的方法来创建对象的。这些核心的方法都是在 AbstractAutowireCapableBeanFactory 中实现,下图便是 doCreateBean 方法,其中的核心操作有三个: createBeanInstance 、populateBean、initializeBean

Spring Bean创建和循环依赖

createBeanInstance

Spring Bean创建和循环依赖

createBeanInstance 是创建 Bean 对象的方法,这里最终调用的是 instantiateBean 方法,最终的调用栈如下:

AbstractAutowireCapableBeanFactory.instantiate
 -> SimpleInstantiationStrategy.instantiate
     -> BeanUtils.instantiateClass
          -> ctor.newInstance

populateBean

populateBean 是设置 Bean 属性的方法,如下图所示 autowireByName autowireByType 两个方法即是自动注入的方法,以 autowireByName 为例,获取属性是以 getBean 的方式从 IOC 容器中获取对应的 Bean。

Spring Bean创建和循环依赖

initializeBean

初始化 Bean 是在实例化之后的操作,在初始化之前和之后便是 BeanPostProcessor 的操作,初始化的操作便是 invokeInitMethods 的初始化方法。

# 在初始化之前和之后执行
applyBeanPostProcessorsBeforeInitialization
applyBeanPostProcessorsAfterInitialization

初始化 Bean 的操作

Spring Bean创建和循环依赖

初始化之前和之后的操作方法:

Spring Bean创建和循环依赖

循环依赖问题

循环依赖是绕不开的话题,循环依赖的问题具体的表现形式如下:

Spring Bean创建和循环依赖

在讲循环依赖如何结果之前,还是涉及到 Bean 是如何创建的,如下图所示的过程就是解决循环依赖的过程。

Spring Bean创建和循环依赖

  •  1 在创建 A 对象时,需要在 populateBean 填充属性时触发获取 B 对象的操作,这里说一下会在 createBeanInstance 方法中将对象的构造方法放进 * 缓存中。

  • 2 在经历了一轮 getBean 和 createBean 之后再次执行到属性赋值操作 populateBean,此时会再次触发获取 A 对象的操作,此时再去获取 A 对象时,会从 * 缓存中创建一个半成品 A 对象放进二级缓存中并删除 * 缓存,并做返回,此时 B 对象得到属性填充,完成赋值后放进一级缓存中,并将 B 对象返回到 1 步骤。

  • 3 第一步的创建 A 对象继续,完成属性赋值后,会将对象放进一级缓存中,并删除二级缓存。 创建 Bean 的过程如下图所示,Abstra ctAutowireCapableBeanFactory.doCreateBean 方法核心内容如下:

Spring Bean创建和循环依赖

获取单例 Bean 的方法:

Spring Bean创建和循环依赖

初始化的方法如下所示:

Spring Bean创建和循环依赖

通过以上的三个步骤,就实现了循环依赖的问题解决,也完成了 Bean 对象的创建过程。

Spring Bean创建和循环依赖

为什么要使用 * 缓存呢,说到底是要解决以下问题:

  • 1 如果采用了一级缓存,如果没有存在循环依赖的问题,确实是可以的。如果有存在前图中的循环依赖问题,那么就无法解决了,就只能采用两级缓存才能解决了。

  • 2 如果使用了两级缓存,确实能解决一部分的问题。但是 Bean 被 AOP 代理,再使用两级缓存就不能解决问题了,必须采用 * 缓存。

Spring Bean创建和循环依赖

来源:https://juejin.cn/post/7083689894089850893

标签:Spring,Bean,创建,循环,依赖
0
投稿

猜你喜欢

  • java最新版本连接mysql失败的解决过程

    2022-05-21 17:29:58
  • Java与Kotlin互调原理讲解

    2023-08-19 00:07:41
  • SpringBoot接入支付宝支付的方法步骤

    2022-02-16 05:34:16
  • Android Studio项目适配AndroidX(Android 9.0)的方法步骤

    2022-10-30 12:01:03
  • maven中配置项目的jdk版本无效的排查方式

    2023-07-18 21:43:42
  • 基于IDEA中格式化代码的快捷键分享

    2022-08-15 14:58:03
  • 详解Maven profile配置管理及激活profile的几种方式

    2022-07-01 08:54:46
  • Java中ArrayList和LinkedList之间的区别_动力节点Java学院整理

    2023-03-30 18:16:29
  • Springboot webscoket自定义定时器

    2023-02-12 05:34:02
  • 解决Springboot get请求是参数过长的情况

    2023-11-27 16:45:37
  • Java对象传递与返回的细节问题详析

    2023-04-07 16:42:50
  • Java并发编程之线程安全性

    2021-12-22 07:43:41
  • C#获取系统版本信息方法

    2022-12-13 04:45:20
  • java数据类型和运算符的深入讲解

    2021-09-14 07:06:08
  • c#反射调用方法示例

    2022-07-14 15:28:40
  • 聊聊Java的switch为什么不支持long

    2023-08-24 17:35:14
  • Java日常练习题,每天进步一点点(8)

    2022-04-15 16:40:26
  • C#利用Task实现任务超时多任务一起执行的方法

    2023-07-04 20:03:38
  • Kotlin Flow操作符及基本使用详解

    2022-08-24 16:32:30
  • C#之IP地址和整数互转的小例子

    2023-11-21 05:49:19
  • asp之家 软件编程 m.aspxhome.com