【Spring】三级缓存

news2024/10/5 0:19:59

目录标题

  • 触发所有未加载的实例a - 开始
  • getBean( doGetBean) - 获取单例bean
    • getSingleton() - 获取单例bean
    • createBean(doCreateBean) - 创建bean
      • createBeanInstance - 创建并返回bean
      • addSingletonFactory -放三级缓存
      • populateBean - 属性设值
        • applyPropertyValues - 设值属性
          • 初始化b开始
            • 从缓存中获取b
            • 创建bean-b实例
            • 提前暴露bean-b
            • b 属性设值
            • 放入一级缓存里面
          • 初始化b结束
          • image.png
      • addSingleton- 放一级缓存
  • 触发所有未加载的实例a - 结束
  • 触发所有未加载的实例b - 开始
  • 触发所有未加载的实例b - 结束

结合文章:循环依赖

测试代码如下:

public class A {
    private B b;

    public B getB() {
        return b;
    }

    public void setB(B b) {
        this.b = b;
    }

    public A() {
        System.out.println("---A created success");
    }
}
public class B {
    private A a;

    public A getA() {
        return a;
    }

    public void setA(A a) {
        this.a = a;
    }
    
    public B() {
        System.out.println("---B created success");

    }
}
public class ClientSpringContainer {


    public static void main(String[] args) {
        sampleDemo();
    }


    private static void sampleDemo() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        A a = context.getBean("a", A.class);
        B b = context.getBean("b", B.class);
    }
}

执行refresh 方法
image.png
执行finishBeanFactoryInitialization 方法
image.png
执行preInstantiateSingletons 方法
image.png

触发所有未加载的实例a - 开始

image.png

getBean( doGetBean) - 获取单例bean

实际上就是通过 doGetBean ,先进行 bean-a 的初始化

getSingleton() - 获取单例bean

去缓存查看时候有 bean - a
image.png
实际上就是通过双重校验锁,去查看一级缓存中是否有 bean-a 并且没有在创建中 ,所以就返回 null
image.png
由于返回了 null ,则 继续往下走,去创建bean-a实例
image.png由于我们 bean-a 是单例的,所以就执行下面的语句块
image.png
再进入内部,发现返回的其实就是执行的就是传参的 createBean(beanName, mbd, args)
image.png
image.png

createBean(doCreateBean) - 创建bean

image.png

createBeanInstance - 创建并返回bean

先执行的是 createBeanInstance,里面是通过构造函数去创建一个bean实例
image.png

addSingletonFactory -放三级缓存

继续,需要暴露出这个bean-a到 三级缓存中,此时我们是有了bean-a的实例:A@2321
image.png

  1. 往三级缓存中放入 a - lamdba@2337
  2. 删除二级缓存

image.png

populateBean - 属性设值

image.png

  1. 先解析看看bean -a 需要那些属性
  2. 在进行设值

image.png

applyPropertyValues - 设值属性

image.png
resolveValueIfNecessary 实际上调用了 resolveReference
image.png
resolveReference 也是通过beanFactory 中获取bean
image.png


初始化b开始

而由于此时工厂里面没有bean-b,没有进行初始化
实际上是调用了doGetBean,又开始了 实例化 bean-b的过程,getBean
image.png

从缓存中获取b

查看一级缓存中是否存在bean-b,返回null
image.png

创建bean-b实例

相当于重复了createBean
由于我们在前一步返回的是null,所以就去执行else语句块的内容
image.png
image.png
常见的是单例bean,进入方法,执行的是createBean方法
image.png
image.png
image.png
调用了doCreateBean方法
image.png
createBeanInstance , B@2627
image.png

提前暴露bean-b

addSingletonFactory
image.png
三级缓存中放入 b - lambda@2644
image.png
此处我们也可以看到在三级缓存中有两个
image.png

b 属性设值

调用 populateBean
image.png
applyPropertyValues
image.png
这里我们可以看到 b 是需要a的(符合我们 前面的需求:a b 互相引用)
image.png
applyPropertyValues 里面又调用了 resolveValueIfNecessary
image.png
resolveValueIfNecessary 又调用了 resolveReference
image.png
resolveReference 调用了 beanFactory.getBean,getBean又是通过doGetBean去获取
image.png
image.png
image.png
先从一级缓存中去获取bean-a ,返回null
image.png
由于一级缓存中没有且a在创建中,执行if语句块
image.png
查看二级缓存中是否有a,没有,执行if 语句块
image.png
再从三级缓存中去获取a, 这里是能够获取从三级缓存中获取到的点击访问
image.png
image.png

  1. a ,三级缓存中的实例 lambda@2337 对应的 实例 A@2321
  2. 放入二级缓存中去 A@2321,此时就已经把a放入二级缓存里面了
  3. 删除三级缓存的内容
  4. 返回缓存中的实例 A@2321

image.png
由于能够从三级缓存中去获取到半成品a,A@2321
image.png
doGetBean 返回 从三级缓存中获取到的A@2321,所以执行if语句快,发现最后返回的是bean,bean是通过getObjectForBeanInstance 去获取的
image.png
getObjectForBeanInstance,又去调用了 super.getObjectForBeanInstance
image.png
getObjectForBeanInstance 就是返回了 A@2321
image.png
doGetBean 结束了,返回了b需要的属性 a(虽然是半成品 A@2321)
image.png
resolveReference 结束,返回 A@2321
image.png
resolveValueIfNecessary结束,返回 A@2321
image.png
退回到applyPropertyValues
image.png
完成属性b设值a( A@2321)
image.png
此时populateBean
(回顾:此时就完成了b的setter注入a),完成了b初始化
image.png
继续,由于在前面,bean-b进行了提前暴露,执行if语句块,所以我们这次flase(意味不需要提前暴露了)
image.png
执行getSingleton, 由于从一级缓存中获取不到,且b在创建中,执行if语句块
image.png
从二级缓存中获取bean-b(肯定是没有的),下图中可以看到我们在二级缓存中也获取不到bean-b,并且不需要提前暴露了,所以不需要执行if语句块
image.png
所以就直接返回null
image.png
返回B@2627
image.png
此时我们就结束了对createBean ,并返回B@2627
image.png
于是我们就能够从三级缓存中去获取到b了
返回b 的 getSingleton,此时就是 B@2627
image.png

放入一级缓存里面

而且,此时我们这个是新创建的bean ,因此 newSingleton = true,执行addSingleton
image.png

  1. 放入一级缓存 b - B@2627
  2. 移除三级缓存
  3. 移除二级缓存

image.png
getSingleton 结束,获取到了 b实例 B@2627
image.png
doGetBean 结束,返回 b实例 B@2627,也就是这一步结束了完成b的初始化
image.png

初始化b结束

那么,接下来,继续完成a的初始化。
resolveReference 结束,返回 b实例 B@2627
image.png
resolveValueIfNecessary结束,返回 b实例 B@2627
image.png
设值a的属性b
image.png
populateBean 结束,完成属性赋值
image.png


初始化a ,A@2321
image.png
前面我们说过我们已经提前暴露了a到三级缓存池里面放到三级缓存池
image.png
执行 getSingleton ,由于
一级缓存里面没有a,且a在创建中,所以 执行if语句块
image.png
由于我们在二级缓存里面能够找到a,if语句就不执行了,因为已经完成了对a的放入二级缓存池

image.png

返回二级缓存池中的对象,A@2321
image.png
于是我们就有了早期暴露对象exposedObject,A@2321,doCreateBean结束
image.png
createBean 结束
image.png
doGetBean结束,返回到getSingleton
image.png
由于这是一个新创建的bean,newSingleton = true,执行addSingleton
image.png

addSingleton- 放一级缓存

  1. a 放入一级缓存:a - A@2321
  2. 移除二级缓存
  3. 移除三级缓存

image.png
getSingleton 结束
image.png
doGetBean 结束
image.png

触发所有未加载的实例a - 结束

image.png

触发所有未加载的实例b - 开始

image.png
image.png
执行getSingleton
image.png
此时,我们的b已经放入了一级缓存了哦,此处就已经完成了b放入一级缓存池,不执行if语句块,返回B@2627
image.png
而我们getGetBean的返回对象bean,就是getSingleton 返回的对象B@2627
image.png

触发所有未加载的实例b - 结束

image.png


preInstantiateSingletons 后面一个循环的语句块,由于这次我们关注的是“循环依赖”,就不着重分析这块 就直接过了
image.png
finishBeanFactoryInitialization 执行结束
image.png
refresh 执行结束
image.png
ClassPathXmlApplicationContext 执行结束
image.png


断点数量如下:
image.png

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

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

相关文章

循环测试之旅 —— 深度解析Pytest插件 pytest-repeat!

在软件开发中,测试的重要性不言而喻。而为了提高测试的鲁棒性和可靠性,Pytest插件 pytest-repeat 应运而生。这个插件可以帮助你轻松实现测试用例的循环运行,以更全面地评估代码的稳定性。本文将深入介绍 pytest-repeat 插件的基本用法和实际…

vtkPolyData 生成轮廓线

PolyData 的轮廓用法实战 #include <vtkActor.h> #include <vtkCutter.h> #include <vtkMath.h> #include <vtkNamedColors.h> #include <vtkNew.h> #include <vtkPlane.h> #include <vtkPolyDataMapper.h> #include <vtkPropert…

探索设计模式的魅力:迭代器模式让你轻松驾驭复杂数据集合

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;并且坚持默默的做事。 文章目录 一、&#x1f4a1; 引言二、原理与结构 &#x1f4da;&#x1f465; 迭代器模式的关…

Matlab|基于支持向量机的电力短期负荷预测【最小二乘、标准粒子群、改进粒子群】

目录 主要内容 部分代码 结果一览 下载链接 主要内容 该程序主要是对电力短期负荷进行预测&#xff0c;采用三种方法&#xff0c;分别是最小二乘支持向量机&#xff08;LSSVM&#xff09;、标准粒子群算法支持向量机和改进粒子群算法支持向量机三种方法对负荷进行…

Eclipse - Colors and Fonts

Eclipse - Colors and Fonts References 编码最好使用等宽字体&#xff0c;Ubuntu 下自带的 Ubuntu Mono 可以使用。更换字体时看到名字里面带有 Mono 的基本都是等宽字体。 Window -> Preferences -> General -> Appearance -> Colors and Fonts -> C/C ->…

Java——IO流

目录 一、IO流的概述 1、IO流的分类 1.1、纯文本文件 2、小结 二、IO流的体系结构 三、字节流 1、FileOutputStream&#xff08;字节输出流&#xff09; 2、FileOutputStream写出数据的细节 3、FileOutputStream写数据的3种方式 3.1、一次写一个字节数据 3.2、一次写…

【网络安全 | 网络协议】一文讲清HTTP协议

HTTP概念简述 HTTP&#xff08;Hypertext Transfer Protocol&#xff09;协议&#xff0c;又称超文本传输协议&#xff0c;用于传输文本、图像、音频、视频以及其他多媒体文件。它是Web应用程序通信的基础&#xff0c;通过HTTP协议&#xff0c;Web浏览器可以向Web服务器发起请…

通俗易懂的L0范数和L1范数及其Python实现

定义 L0 范数&#xff08;L0-Norm&#xff09; L0 范数并不是真正意义上的一个范数&#xff0c;因为它不满足范数的三角不等式性质&#xff0c;但它在数学优化和信号处理等领域有着实际的应用。L0 范数指的是向量中非零元素的个数。它通常用来度量向量的稀疏性。数学上表示为…

合理利用pandas来简化大量请求数据组装工作

工作场景 本次我们开发了一个新功能&#xff0c;为了验证它是否合理&#xff0c;我们需要从线上导出一批真实的用户数据来进行模拟请求&#xff0c;以此来验证功能的完整性。 例如一个很简单的功能&#xff0c;我们是一个对学生成绩进行数据分析的系统&#xff0c;各学校会将…

prometheus+mysql_exporter监控mysql

prometheus+mysql_exporter监控mysql 一.安装mysql 1.下载:wget -i -c http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm 2.安装客户端:yum -y install mysql57-community-release-el7-10.noarch.rpm 3.安装服务端:yum -y install mysql-community-se…

mysql 2-1

添加数据 方式二 更新数据 删除数据 小结 计算列 数据类型 可选属性 适用场景 如何选择 浮点类型 存在精度问题 定点数介绍 BIT类型 日期与时间类型 YEAR类型 DATA类型 TIME类型 DATATIME TIMESTAMP 文本字符串类型 适用场景 TEXT类型

JavaWeb-JDBC-练习

一、环境准备 1、数据库表 tb_brand 2、实体类 Brand 最后注意使用get、set方法和toString 二、实现功能 1、查询所有数据 2、添加数据 3、根据id修改 4、根据id删除

【类与对象 -2】学习类的6个默认成员函数中的构造函数与析构函数

目录 1.类的6个默认成员函数 2.构造函数 2.1概念 2.2特性 3.析构函数 3.1析构函数的概念 3.2特性 1.类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&#xff0c;…

红队学习笔记Day6 --->干货分享

今天看到这样的一个东西&#xff0c;好好好&#xff0c;有点恐怖&#x1f613;&#x1f613;&#x1f631;&#x1f631;&#x1f631;&#x1f631; 我就想网安是不是也有这种东西&#xff1f; 我来试试 icmp&#xff0c;RDP&#xff0c;arp&#xff0c;dhcp&#xff0c;nat&a…

C语言系列-带有副作用的宏参数#和##命名约定宏替换的规则

&#x1f308;个人主页: 会编辑的果子君 &#x1f4ab;个人格言:“成为自己未来的主人~” 目录 带有副作用的宏参数 宏替换的规则 宏函数的对比 #和## #运算符 ##运算符 命名约定 #undef 带有副作用的宏参数 当宏参数在宏的定义中出现超过一次的时候&#xff0c;如果…

2024/2/19

作业1&#xff1a;使用fread和fwrite完成两个图片文件的拷贝 代码&#xff1a; #include <myhead.h>int main(int argc, const char *argv[]) {FILE *fpNULL;//以只读的形式打开文件if(( fpfopen("./dashuai.bmp","r")) NULL){perror("fopen…

【lesson62】网络通信UdpSocket版

文章目录 UdpSocketUdpServer.hppUdpServer类成员变量解释成员函数解释 UdpServer的实现ServerIinit的实现socketbindhtonsinet_addr具体实现 ServerStart的实现recvfromsendtontohsinet_ntoa具体实现 ~UdpServer函数实现UdpServer.hpp整体完整代码 UdpServer.ccUdpClient.ccTh…

Java学习--黑马SpringBoot3课程个人总结-2024-02-12

1.环境准备 出现报错 Vue 引入路径正确的&#xff0c;但一直报错&#xff1a; Already included file name ‘‘ differs from file name ‘‘ only in casing. 解决方案来自此链接 2.注册界面的搭建 代码如下 <script setup> import { User, Lock } from element-plus/…

【C语言】通讯录(静态版本+动态版本)思路解析+完整源代码

通讯录 由于代码比较长&#xff0c;为了增加可读性&#xff0c;分成了contact.h&#xff0c;contact.c&#xff0c;test.c&#xff0c;分别用来声明函数或者类型&#xff0c;实现函数功能&#xff0c;测试代码 contact.h 我们希望通讯录具有增加联系人&#xff0c;删除联系人…

防火墙之firewalld基础

一、firewalld的简介 firewalld防火墙是Centos7系统默认的防火墙管理工具&#xff0c;取代了之前的iptables防火墙&#xff0c;也是工作在网络层&#xff0c;属于包过滤防火墙。 firewalld和iptables都是用来管理防火墙的工具&#xff08;属于用户态&#xff09;来定义防火墙的…