Spring FrameWork从入门到NB -三级缓存解决循环依赖内幕 (二)

news2024/12/25 12:45:20

开始用上一篇文章讲到的Spring依赖注入的步骤,用两个例子来推导一下整个过程,举例子有助于了解真相。

先用一个最简单的例子:没有依赖的单例bean的创建。

推导过程是需要上一篇文章的步骤的,要参照步骤一步一步来。

无依赖的单例Bean的创建

假设要创建单例bean A:

  1. 首先,getBean->deGetBean方法,调用getSingleton(beanName,true)方法。
  2. getSingleton(beanName,true)一次检查一级、二级、三级缓存,都没有A对象,返回null。
  3. 检查Dependon,假设没有设置,不需要创建DependOn对象。
  4. 调用getSingleton(beanName,factory)方法:检查一级缓存中不存在,将当前bean的name放入“正在创建中”列表,调用createBean创建bean。
  5. createBean创建A的实例,检查到当前bean在“正在创建中”列表中,则将当前bean放入三级缓存中。
  6. 调用populateBean进行属性填充,由于A对象没有依赖任何对象,所以不需要注入其他对象,直接完成属性填充。
  7. 调用返回到第4步getSingleton(beanName,factory)方法中,完成bean创建后,将当前bean name从“正在创建中”列表中移除。
  8. 将bean A从三级缓存、二级缓存中移除,放入一级缓存中。
  9. 完成bean A的创建。

循环依赖的单例Bean的创建过程

A依赖B,B依赖A,假设都是属性的互相依赖,即:

@Component
public class A {
    @Autowired
    private B b;
}
@Component
public class B {
    @Autowired
    private A a;
}

个人认为复杂的循环依赖都可以转化为我依赖你、你依赖我这种模式,所以我们还是试图把这个例子说的清楚明白一点,关键步骤用图示的方式说明。

假设首先创建A实例。

  1. 执行到getSingleton(beanName,boolean)方法的时候,三个缓存都空:
    在这里插入图片描述

  2. 然后,接着执行到doCreateBean的时候,会把A的工厂方法放入到三级缓存,如图:
    在这里插入图片描述

  3. 接下来就是populateBean方法,为bean A执行属性填充,查找到需要注入bean B,调用getBean,如图,用蓝色箭头表示,当执行到getSingleton(beanName,boolean)方法的时候,三个缓存中都没有bean B:
    在这里插入图片描述

  4. 继续执行到doCreateBean的时候,会把B的工厂方法放入到三级缓存:
    在这里插入图片描述

  5. 然后到populateBean方法,为bean B执行属性填充,查找到需要注入bean A。

  6. 调用getBean(A),如图,用红色箭头表示,当执行到getSingleton(beanName,boolean)方法的时候,三级缓存中存在bean A,所以,利用工厂方法创建A对象,放入二级缓存,返回bean A,并将A从三级缓存移除:
    在这里插入图片描述

  7. 返回到步骤5,将bean A赋值给bean B的属性a,完成bean B的属性填充。之后返回到第4步,完成bean B的doCreateBean方法,将Bean B放入一级缓存,同时将Bean B从二级、三级缓存移除:
    在这里插入图片描述

这一步完成之后,Bean B完成了创建,也完成了他的属性A的依赖注入,但是注入的Bean A是个半成品,还放在二级缓存中,尚未完成创建。

但是由于Bean A的创建流程还没有结束,所以不会有问题,接下来的步骤会完成Bean A的创建。
8. 流程返回到第3部,bean A的populateBean方法获取到了已经完成创建的bean B对象,完成Bean A的属性注入。
9. 之后继续执行bean A的doCreateBean的后续逻辑,完成Bean A的创建,将Bean A放入到一级缓存,并从二级、三级缓存移除:
在这里插入图片描述

  1. 完成bean A和bean B的创建,完成A、B之间的依赖注入。

小结

用图解的方式说明Spring通过三级缓存解决依赖注入的过程。其实个人理解,对于更加复杂的依赖关系,注入过程无非就是在以上10个步骤之间不断递归调用的过程。

据说有一个问题是,Spring三级缓存的必要性,后面的文章会尝试回答这个问题。

上一篇 Spring FrameWork从入门到NB -三级缓存解决循环依赖内幕 (一)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/688847.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux内核代码60%都是驱动?驱动代码不会造成内核臃肿吗?

为什么内核中驱动占比最高 一、前言二、Linux中避免内核臃肿的措施2.1 交叉编译及SDK包的裁剪2.2 设备树2.3 模块化2.4 硬件抽象层 三、嵌入式Linux的裁剪四、总结 一、前言 今天逛知乎看到这么一个问题:为什么Linux内核代码60%都是驱动? 如果每支持新的设备就加入…

【设计模式】Java设计模式——模板方法模式(Template Pattern)

文章目录 1. 介绍1.1 定义1.2 作用 2. 模式结构2.1 UML类图2.2 模式组成 3. 代码实例3.1 背景3.2 应用 4. 优点5. 缺点6. 应用场景 1. 介绍 1.1 定义 模板方法模式(Template Pattern),又叫模板模式,它属于行为型模式模板方法模式定义一个模板结构&…

Apikit 自学日记:版本管理

功能入口:API管理应用 / 选中某个项目 / 项目管理菜单 / 项目版本管理 项目版本管理功能模块提供对项目级别的版本管理,可新增、删除、对比项目级版本。在创建项目版本号的时候会对整个项目的部分模块数据进行快照保存。可用于每次迭代发布打全局版本号…

ESP32设备驱动-TMF8801激光测距传感器驱动

TMF8801激光测距传感器驱动 文章目录 TMF8801激光测距传感器驱动1、TMF8801介绍2、硬件准备3、软件准备4、驱动实现1、TMF8801介绍 TMF8801 是一款真正的直接飞行时间 (ToF) 传感器系统,采用单一模块化封装,通过亚纳秒光脉冲和抗锯齿“秒表”方法测量往返时间,提供高精度深度…

流量分析工具wireshark-学习笔记

(一)wireshark工具 1、wireshark工具简介 Wireshark是一种开源网络分析工具,它可以让你在计算机网络上捕获和查看数据包,并能帮助你深入了解网络的运行和协议的实现。它可以捕获不同类型的流量,包括以太网、Wi-Fi、TC…

【面试题】面试官问:如果有100个请求,你如何使用Promise控制并发?

大厂面试题分享 面试题库 前后端面试题库 (面试必备) 推荐:★★★★★ 地址:前端面试题库 web前端面试题库 VS java后端面试题库大全 开篇 在现代Web开发中,异步请求已经成为了必不可少的一部分。然而,…

ISP之图像降分辨率

1、图像缩放背景 图像的放大、缩小(简称缩放)是图像处理的一种处理方法。所谓图像缩放是指图像分辨率的改变,它在图像显示、传输、图像分析以及动画制作、电影合成、甚至医学图像处理中都有着相当广泛的应用。比如要在1024 X 768 分辨率的显示器上全屏显示800 X 60…

8.2 电压比较器(2)

五、集成电压比较器 1、集成电压比较器的主要特点和分类 电压比较器可将模拟信号转换成二值信号,即只有高电平和低电平两种状态的离散信号。因此,可用电压比较器作为模拟电路和数字电路的接口电路。集成电压比较器虽然比集成运放的开环增益低&#xff…

强化学习从基础到进阶-案例与实践[6]:演员-评论员算法(advantage actor-critic,A2C),异步A2C、与生成对抗网络的联系等详解

【强化学习原理项目专栏】必看系列:单智能体、多智能体算法原理项目实战、相关技巧(调参、画图等、趣味项目实现、学术应用项目实现 专栏详细介绍:【强化学习原理项目专栏】必看系列:单智能体、多智能体算法原理项目实战、相关技巧…

Arcmap读取nc文件并导出为tif格式

Arcmap读取nc文件并导出为tif格式 前言操作步骤 前言 在使用某一降水数据的时候,发现直接把nc格式的数据拖进Arcmap,查看属性表的时候是空的,点击图上的信息也只会显示一个值,但这个nc数据应该是有很多个值的(我的数据…

Kubernetes - adm搭建 · 保姆级教程

master(2C/4G,cpu核心数要求大于2) 192.168.179.25 docker、kubeadm、kubelet、kubectl、flannel node01(2C/2G) 192.168.179.26 docker、kubeadm、kubelet、kubectl…

【JavaScript】JavaScript中的nodeName、nodeType、nodeValue区别

文章目录 JavaScript中的nodeName、nodeType、nodeValue区别(一)nodeName(二)nodeValue(三)nodeType JS代码demo JavaScript中的nodeName、nodeType、nodeValue区别 (一)nodeName https://www.w3schools.cn/jsref/prop_node_nodename.html 元素节点的 nodeName是标签名称 属性…

ffmpeg windows编译及调试完整版

目录 编译 基础环境准备 依赖环境安装 依赖库安装 X264 fdk-aac X265 ffmpeg-4.3.6 调试 基础项目环境搭建 VS2019项目创建 VS2019项目代码 vs2019配置 VS2019调试 编译 基础环境准备 1、安装vs2019环境 2、安装msys2工具 3、开始菜单启动x86 Native Tools Comm…

从0到1精通自动化测试,pytest自动化测试框架,fixture之autouse=True(十二)

一、前言 平常写自动化用例会写一些前置的fixture操作,用例需要用到就直接传该函数的参数名称就行了。当用例很多的时候,每次都传这个参数,会比较麻烦 fixture里面有个参数autouse,默认是Fasle没开启的,可以设置为Tr…

diffusion model(一)DDPM技术小结 (denoising diffusion probabilistic)

DDPM技术小结 (denoising diffusion probabilistic) 1 从直觉上理解DDPM 在详细推到公式之前,我们先从直觉上理解一下什么是扩散 对于常规的生成模型,如GAN,VAE,它直接从噪声数据生成图像,我们不妨记噪声数据为 z z…

RTX 4060跑分出炉,加量还降价真良心了?

RTX 40 系真正意义上主流平民级显卡 4060 桌面版已确认于本月 29 日推出。 相较于原定的 7 月中旬上市提前了半个月左右,国内售价 2399 元(比 RTX 3060 首发低 100 元)。 从这样的「早产」操作能看出,RTX 40 系显卡拉胯销量表现确…

java并发编程 2:java线程基础知识

目录 创建和运行线程查看进程线程线程运行原理常见方法了解start与runsleep与yield线程优先级joininterrupt不推荐使用的方法 主线程与守护线程线程状态操作系统中的线程状态java中的线程状态 创建和运行线程 方法一: 直接使用 Thread public class CreateThread01 {public s…

使用U盘安装Centos7全流程分享

文章目录 1、下载 centos7 的镜像2、下载老白菜3、插入U盘4、将U盘插入要刷机的电脑中5、获取U盘的启动地址6、正式配置重启7、进入安装界面了,现在就容易7.1 选择中文7.2 点击安装位置,分配磁盘7.3 配置网络和主机7.4 选择开始安装,并配置账…

【第1集】odoo16开发环境搭建

因为博主使用Mac作为开发电脑,因此都以Mac为主。同时本文odoo使用的是16版本,采用python源码进行安装,如需要二进制安装同学,后续有条件可能会出这方面的搭建指导。本文包含四个部分,分别为数据库安装,系统…

C++ bool 类型

文章目录 一. bool 类型二. 三目运算符 一. bool 类型 在 C 中,bool 类型用于表示逻辑值,它只有两个可能的取值:true(真)和 false(假)。bool 类型常用于条件判断和布尔运算中。 C 标准要求 bo…