当前位置: 首页 > news >正文

【Spring】三级缓存

目录标题

  • 触发所有未加载的实例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


流程示例图
在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 域名 SSL 证书信息解析 API 数据接口
  • 练习:鼠标类设计之2_类和接口
  • java并发- volatile关键字
  • 【深度学习】使用tensorflow实现VGG19网络
  • mysql mgr集群多主部署
  • 深度学习与机器学习的关系
  • list链表
  • 【AI学习】LangChain学习
  • ArcGIS学习(八)基于GIS平台的控规编制办法
  • 【Node.js】path 模块进行路径处理
  • UE5中的DataTable说明
  • 剪辑视频调色软件有哪些 剪辑视频软件哪个最好 剪辑视频怎么学 剪辑视频的方法和步骤 会声会影2024 会声会影视频制作教程
  • 【研究生复试】计算机软件工程人工智能研究生复试——资料整理(速记版)——JAVA
  • Sora了解资料
  • OpenHarmony下GN语法普法
  • [case10]使用RSQL实现端到端的动态查询
  • [js高手之路]搞清楚面向对象,必须要理解对象在创建过程中的内存表示
  • 【162天】黑马程序员27天视频学习笔记【Day02-上】
  • 【347天】每日项目总结系列085(2018.01.18)
  • Brief introduction of how to 'Call, Apply and Bind'
  • CSS选择器——伪元素选择器之处理父元素高度及外边距溢出
  • Docker入门(二) - Dockerfile
  • maya建模与骨骼动画快速实现人工鱼
  • Python连接Oracle
  • 构造函数(constructor)与原型链(prototype)关系
  • 机器人定位导航技术 激光SLAM与视觉SLAM谁更胜一筹?
  • 微服务入门【系列视频课程】
  • 因为阿里,他们成了“杭漂”
  • 鱼骨图 - 如何绘制?
  • media数据库操作,可以进行增删改查,实现回收站,隐私照片功能 SharedPreferences存储地址:
  • CMake 入门1/5:基于阿里云 ECS搭建体验环境
  • 哈罗单车融资几十亿元,蚂蚁金服与春华资本加持 ...
  • ​Python 3 新特性:类型注解
  • ​七周四次课(5月9日)iptables filter表案例、iptables nat表应用
  • # Redis 入门到精通(九)-- 主从复制(1)
  • #[Composer学习笔记]Part1:安装composer并通过composer创建一个项目
  • #laravel 通过手动安装依赖PHPExcel#
  • #QT 笔记一
  • (1)SpringCloud 整合Python
  • (二)换源+apt-get基础配置+搜狗拼音
  • (附源码)spring boot火车票售卖系统 毕业设计 211004
  • (附源码)计算机毕业设计高校学生选课系统
  • (力扣记录)1448. 统计二叉树中好节点的数目
  • (转)人的集合论——移山之道
  • (转)如何上传第三方jar包至Maven私服让maven项目可以使用第三方jar包
  • ./indexer: error while loading shared libraries: libmysqlclient.so.18: cannot open shared object fil
  • .NET C# 配置 Options
  • .NET 使用 JustAssembly 比较两个不同版本程序集的 API 变化
  • .net 使用ajax控件后如何调用前端脚本
  • .Net中间语言BeforeFieldInit
  • .sh
  • /*在DataTable中更新、删除数据*/
  • @RequestBody与@RequestParam
  • []新浪博客如何插入代码(其他博客应该也可以)
  • [2018/11/18] Java数据结构(2) 简单排序 冒泡排序 选择排序 插入排序