深度解析 Spring 源码:三级缓存机制探究

在这里插入图片描述

文章目录

    • 一、 三级缓存的概述
    • 二、 三级缓存的实现原理
      • 2.1 创建Bean流程图
      • 2.2 getBean()
      • 2.3 doGetBean()
      • 2.4 createBean()
      • 2.5 doCreateBean()
      • 2.4 getSingleton()
    • 三、 三级缓存的使用场景与注意事项
      • 3.1 在实际开发中如何使用三级缓存
      • 3.2 三级缓存可能出现的问题及解决方法

一、 三级缓存的概述

概念:

三级缓存是指用于管理 Bean 对象创建过程中不同阶段的缓存机制。

  1. 一级缓存(singletonObjects):存储已经完全初始化的单例 Bean 对象。
  2. 二级缓存(earlySingletonObjects):存储已经实例化但尚未完全初始化的单例 Bean 对象。
  3. 三级缓存(singletonFactories):存储 Bean 对象的创建工厂,用于在创建过程中检测循环依赖。

意义:

  1. 提高性能: 通过缓存已经创建的 Bean 对象,Spring 可以在后续的请求中直接返回缓存的对象,避免重复创建,从而提高了系统的性能和响应速度。
  2. 解决循环依赖: 三级缓存中的三级缓存(singletonFactories)用于解决循环依赖问题。当 A Bean 依赖于 B Bean,而 B Bean 又依赖于 A Bean 时,Spring 可以在创建 A Bean 的过程中将其提前放入三级缓存,以解决循环依赖的问题。
  3. 实现懒加载: 二级缓存(earlySingletonObjects)可以实现 Bean 的懒加载,即在 Bean 第一次被请求时才进行初始化,而不是在容器启动时就立即创建所有的 Bean 对象。
  4. 保证单例: 通过一级缓存(singletonObjects)中存储的已初始化的单例 Bean 对象,Spring 可以保证在应用程序中只存在一个实例,实现了单例模式的效果。

二、 三级缓存的实现原理

由于创建Bean的代码量非常多,本文仅展示与三级缓存有关的代码。

读者想要对三级缓存了解更加深刻,可以自行创建循环依赖的Bean,根据调试来解读代码。

2.1 创建Bean流程图

这里仅仅展示创建Bean的大致流程图,想深入了解的读者可以自行解读源码。

在这里插入图片描述

2.2 getBean()

在这里插入图片描述

2.3 doGetBean()

在这里插入图片描述

在这里插入图片描述

2.4 createBean()

在这里插入图片描述

2.5 doCreateBean()

在这里插入图片描述

在这里插入图片描述

2.4 getSingleton()

在这里插入图片描述

在这里插入图片描述

三、 三级缓存的使用场景与注意事项

3.1 在实际开发中如何使用三级缓存

在实际开发中,我们通常不需要直接操作 Spring 的三级缓存,因为 Spring 框架会自动管理这些缓存。只需要通过合适的配置和编码实践来确保 bean 的正确创建和管理即可。

在实际开发中使用 Spring 的三级缓存简单Demo

假设有一个简单的服务接口 UserService 和其实现类 UserServiceImpl,将使用 Spring 来管理它们的依赖注入单例管理

public interface UserService {
    void addUser(String username);
}

public class UserServiceImpl implements UserService {
    private List<String> users = new ArrayList<>();

    @Override
    public void addUser(String username) {
        users.add(username);
    }
}

现在配置 Spring 容器并将 UserServiceImpl 注入到容器中:

/*
* 定义了一个配置类 AppConfig,在其中通过 @Bean 注解定义了一个名为 userService 的 Bean,并指定了它的实现类为 UserServiceImpl
*/
@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
    @Bean
    public UserService userService() {
        return new UserServiceImpl();
    }
}

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
		// Spring 默认情况下会使用单例模式管理 Bean,所以每次获取 UserService Bean 都会得到同一个实例
        // 从 Spring 应用上下文中获取一个名为 userService 的 Bean,其类型为 UserService。在 AppConfig 中定义了 userService Bean,并且它的实现类为 UserServiceImpl,所以这里实际上是获取了一个 UserServiceImpl 类型的对象
        UserService userService1 = context.getBean(UserService.class);
        userService1.addUser("Alice");
		// 再次从 Spring 应用上下文中获取一个 UserService 类型的 Bean,实际上是获取了之前已经创建过的同一个 UserServiceImpl 类型的对象
        UserService userService2 = context.getBean(UserService.class);
        userService2.addUser("Bob");

        // 可给对象做一些其它额外的操作
		// 关闭了 Spring 应用上下文,释放资源
        context.close();
    }
}

分析 Spring 是如何使用三级缓存的:

  1. BeanDefinition 缓存: 在 Spring 容器启动时,Spring 会解析所有的 bean 定义(BeanDefinition),并将其缓存起来。这个缓存存储了 bean 的元数据信息,如类名、依赖关系等。当我们通过 @Bean 或者其他方式声明一个 bean 时,Spring 首先会检查 BeanDefinition 缓存中是否存在该 bean 的定义,如果存在,则直接使用该定义,否则会根据配置信息创建一个新的 BeanDefinition。
  2. 单例对象实例缓存: 当我们通过 Spring 容器获取一个单例 bean 时,Spring 首先会检查单例对象实例缓存中是否已经存在该 bean 的实例。如果存在,则直接返回缓存中的实例,否则会根据 BeanDefinition 中的信息创建一个新的 bean 实例,并放入缓存中。
  3. 早期的单例对象实例缓存: 在 bean 的创建过程中,Spring 可能需要解决循环依赖等问题。为了解决这些问题,Spring 使用了早期的单例对象实例缓存。当 bean 的创建过程中遇到循环依赖时,Spring 会将正在创建的 bean 提前暴露给其他需要它的 bean,从而解决循环依赖的问题。

3.2 三级缓存可能出现的问题及解决方法

在 Spring 中,虽然没有官方定义的 “三级缓存” 概念,但可以类比于 MyBatis 中的缓存机制。

从 Spring 的缓存相关模块(如 Spring Cache)的角度来看,也存在一些可能的问题以及解决方法。

  1. 缓存数据不一致性问题
    • 问题:当使用 Spring Cache 缓存方法的返回结果时,如果在缓存数据过期前发生了数据变更(如数据库更新),则缓存中的数据与实际数据不一致。
    • 解决方法:
      • 手动清除缓存:在数据变更操作后,手动清除相应的缓存,保持缓存与数据库数据的一致性。
      • 使用缓存刷新策略:在 Spring Cache 中,可以通过配置缓存刷新策略,定期或在特定触发条件下刷新缓存,使缓存中的数据保持最新。
  2. 缓存击穿问题
    • 问题:当某个缓存项过期时,同时有大量并发请求访问该缓存项,可能导致大量请求直接访问底层数据源(如数据库),增加系统负载。
    • 解决方法:
      • 设置合适的缓存过期时间:根据业务场景和系统负载情况,设置合适的缓存过期时间,避免大量缓存同时失效。
      • 使用互斥锁机制:在缓存项失效时,使用互斥锁机制保证只有一个线程能够重新加载缓存项,其他线程等待该线程加载完数据后再从缓存中获取。
  3. 缓存雪崩问题
    • 问题:当大量缓存项同时失效时,可能导致大量请求直接访问底层数据源,从而造成系统压力过大。
    • 解决方法:
      • 使用分布式缓存:如果系统是分布式的,考虑使用分布式缓存技术,将缓存分布在多个节点上,避免单点故障。
      • 设置随机过期时间:在设置缓存过期时间时,可以稍微随机一些,避免大量缓存同时失效。
      • 使用熔断机制:当系统压力过大时,可以使用熔断机制暂时关闭对底层数据源的访问,避免系统崩溃。

今是生活,今是动力,今是行为,今是创作

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

特征值eigenvalue与特征向量eigenvector

特征值&#xff0c;特征向量概念 在线性代数中&#xff0c;对于一个给定的线性变换A&#xff0c;他的特征向量v经过这个线性变换的作用之后&#xff0c;得到的新向量仍然与原来的 v v v保持在同一条直线上。但长度或方向也许会改变。即&#xff1a; A v Av Av λ v \lambda…

Android开发——Fragment

Demo fragment_blank.xml <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_pare…

Java Web3-2 - tomcat

https://github.com/heibaiying/Full-Stack-Notes/blob/master/notes/Tomcat_架构解析.md https://zhuanlan.zhihu.com/p/40249834 早期&#xff0c;web技术主要用于浏览静态页面 时间发展&#xff0c;用户已经不满足于仅浏览静态页面。用户需要一些交互操作&#xff0c;获取…

追溯历史:SIEM 中的生成式人工智能革命

作者&#xff1a;来自 Elastic Mike Nichols, Mike Paquette 网络安全领域仿佛是现实世界的一个映射&#xff0c;安全运营中心&#xff08;security operation center - SOC&#xff09;就像是你的数字警察局。网络安全分析师就像是警察&#xff0c;他们的工作是阻止网络犯罪分…

【Web】DASCTF X GFCTF 2024|四月开启第一局 题解

目录 EasySignin cool_index web1234 web4打破防了&#x1f92e;&#xff0c;应该很接近解出来了&#xff0c;感兴趣的师傅续上吧 EasySignin 先随便注册个账号登录&#xff0c;然后拿bp抓包改密码(username改成admin) 然后admin / 1234567登录 康好康的图片功能可以打SS…

ros仿真启动小龟

1.启动RosMaster&#xff08;管理Ros中各个节点的“大管家”&#xff0c;每次启动Ros时需要首先启动RosMaster&#xff09; roscorefangfang-inspiron-5580:~/ros2/download/rosdistro$ roscore ... logging to /home/fang/.ros/log/6ec2d790-fe1d-11ee-aba8-1c1bb5cdec7c/ros…

MySQL-实验-单表、多表数据查询和嵌套查询

目录 0.简单子查询 &#xff08;1&#xff09;带比较运算符的子查询 &#xff08;2&#xff09;关键字子查询 1.多表查询 3.子查询 4.多表子查询 0.简单子查询 &#xff08;1&#xff09;带比较运算符的子查询 在右侧编辑器补充代码&#xff0c;查询大于所有平均年龄的员…

10 SQL进阶 -- 综合练习题 -- 10道经典SQL题目,配套数据与解答

1. 创建表结构和导入数据 1.1 新建数据库 1.2 执行建表语句 点击下方链接直接下载创建数据表脚本:http://tianchi-media.oss-cn-beijing.aliyuncs.com/dragonball/SQL/create_table.sql 执行建表语句执行成功查看创建的表1.3 导入数据 点击下方链接直接下载插入数据脚本:htt…

VBA脚本终章编译器崩溃

一、介绍 本篇文章为VBA脚本隐藏技术的最后一篇&#xff0c;将介绍如何在保证VBA脚本正常执行的情况下&#xff0c;使分析人员无法打开编译器。 那么为什么需要分析人员无法打开编译器呢&#xff1f; 首先&#xff0c;我们需要引入一个知识点。 在上篇《VBA隐藏技术stompin…

笔记本wifi连接外网 网线连接办公内网 设置路由实现内外网可同时访问

工作提供的办公网络是企业内网,接上企业内网网线后 通过无线在连接手机wifi ,会发现内外网无法同时访问,我自己电脑是接上内网网线 也是只能访问外网,除非把外网无线暂时关闭,才可以访问内网 频繁切换很不方便 1.查看外网无线 wifi网卡信息 IPv4 地址: 192.168.18.114 IP…

数据结构学习记录

数据结构 数组 & 链表 相连性 | 指向性 数组可以迅速定位到数组中某一个节点的位置 链表则需要通过前一个元素指向下一个元素&#xff0c;需要前后依赖顺序查找&#xff0c;效率较低 实现链表 // head > node1 > node2 > ... > nullclass Node {constructo…

AI原生时代,操作系统为何是创新之源?

一直以来&#xff0c;操作系统都是软件行业皇冠上的明珠。 从上世纪40、50年代&#xff0c;汇编语言和汇编器实现软件管理硬件&#xff0c;操作系统的雏形出现&#xff1b;到60年代&#xff0c;高级编程语言和编译器诞生&#xff0c;开发者通过操作系统用更接近人的表达方式去…

面向对象(一)

一.类与对象的定义 (1)类(设计图):是对象共同特征的描述: (2)对象:是真实存在的具体东西。 在Java中,必须先设计类&#xff0c;才能获取对象。 二.如何定义类 public class 类名{1.成员变量(代表属性,一般是名词) 2.成员方法(代表行为,一般是动词) 3.构造器 4.代码块 5.内部…

Liunx入门学习 之 基础操作指令讲解(小白必看)

股票的规律找到了&#xff0c;不是涨就是跌 一、Linux下基本指令 1.ls 指令 2.pwd 命令 3.cd 指令 4.touch 指令 5.mkdir 指令 6.rmdir指令 && rm 指令 7.man 指令 8.cp 指令 9.mv指令 10.cat 11.more 指令 12.less 指令 13.head 指令 14.tail 指令 15…

论文解读-Contiguitas: The Pursuit of Physical Memory Contiguity in Datacenters

研究背景&#xff1a; 在内存容量飞速增长的背景下&#xff0c;使用小页管理内存会带来巨大的内存管理开销&#xff08;地址转换开销高&#xff09;。近些年来不少研究尝试给应用分配大段连续区域&#xff0c;或者改善页表结构&#xff08;如使用hash结构的页表&#xff09;以降…

质谱原理与仪器2-笔记

质谱原理与仪器2-笔记 常见电离源电子轰击电离源(EI)碎片峰的产生典型的EI质谱图 化学电离源(CI)快原子轰击源(FAB)基体辅助激光解析电离(MALDI)典型的MALDI质谱图 大气压电离源(API)电喷雾离子源(ESI)大气压化学电离源(APCI)APCI的正负离子模式 大气压光电离源(APPI) 常见电离…

玄子Share-计算机网络参考模型

玄子Share-计算机网络参考模型 分层思想 利用七层参考模型&#xff0c;便于在网络通信过程中&#xff0c;快速的分析问题&#xff0c;定位问题并解决问题 将复杂的流程分解为几个功能相对单一的子过程 整个流程更加清晰&#xff0c;复杂问题简单化 更容易发现问题并针对性的…

线上频繁fullgc问题-SpringActuator的坑

整体复盘 一个不算普通的周五中午&#xff0c;同事收到了大量了cpu异常的报警。根据报警表现和通过arthas查看&#xff0c;很明显的问题就是内存不足&#xff0c;疯狂无效gc。而且结合arthas和gc日志查看&#xff0c;老年代打满了&#xff0c;gc不了一点。既然问题是内存问题&…

Python练习03

题目 解题思路 Demo58 通过字符串切片来进行反转操作 def _reverse():"""这是一个反转整数的函数"""num input("请输入想要反转的整数")print(num[::-1]) 运行结果 Demo61 首先制作一个判断边长的函数&#xff0c;通过三角形两边…

又成长了,异常掉电踩到了MySQL主从同步的坑!

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…