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

基于Spring Boot的多级缓存架构实现

基于Spring Boot的多级缓存架构实现

以下是一个基于Spring Boot的多级缓存架构实现示例


多级缓存架构实现方案

1. 依赖配置(pom.xml)
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>caffeine</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2. 缓存配置类
@Configuration
@EnableCaching
public class MultiLevelCacheConfig {// 一级缓存(本地缓存)@Beanpublic CacheManager caffeineCacheManager() {CaffeineCacheManager manager = new CaffeineCacheManager();manager.setCaffeine(Caffeine.newBuilder().maximumSize(1000).expireAfterWrite(30, TimeUnit.SECONDS)); // 本地缓存比Redis缓存更短return manager;}// 二级缓存(Redis缓存)@Beanpublic CacheManager redisCacheManager(RedisConnectionFactory factory) {RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(5)).serializeValuesWith(SerializationPair.fromSerializer(RedisSerializer.json()));return RedisCacheManager.builder(factory).cacheDefaults(config).transactionAware().build();}// 组合缓存管理器@Bean@Primarypublic CacheManager multiLevelCacheManager(@Qualifier("caffeineCacheManager") CacheManager level1,@Qualifier("redisCacheManager") CacheManager level2) {return new MultiLevelCacheManager(level1, level2);}
}
3. 多级缓存管理器实现
public class MultiLevelCacheManager implements CacheManager {private final CacheManager level1; // 本地缓存private final CacheManager level2; // Redis缓存private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>();public MultiLevelCacheManager(CacheManager level1, CacheManager level2) {this.level1 = level1;this.level2 = level2;}@Overridepublic Cache getCache(String name) {return cacheMap.computeIfAbsent(name, key -> new MultiLevelCache(level1.getCache(name), level2.getCache(name)));}@Overridepublic Collection<String> getCacheNames() {return Stream.concat(level1.getCacheNames().stream(),level2.getCacheNames().stream()).collect(Collectors.toSet());}// 多级缓存实现static class MultiLevelCache implements Cache {private final Cache level1;private final Cache level2;private final String name;public MultiLevelCache(Cache level1, Cache level2) {this.level1 = level1 != null ? level1 : new NoOpCache();this.level2 = level2 != null ? level2 : new NoOpCache();this.name = level1.getName() + ":" + level2.getName();}@Overridepublic String getName() {return name;}@Overridepublic Object getNativeCache() {return this;}@Overridepublic ValueWrapper get(Object key) {// 先查一级缓存ValueWrapper value = level1.get(key);if (value == null) {// 二级缓存查询value = level2.get(key);if (value != null) {// 回填一级缓存level1.put(key, value.get());}}return value;}@Overridepublic <T> T get(Object key, Class<T> type) {// 实现逻辑类似get方法T value = level1.get(key, type);if (value == null) {value = level2.get(key, type);if (value != null) {level1.put(key, value);}}return value;}@Overridepublic void put(Object key, Object value) {// 同时写入两级缓存level1.put(key, value);level2.put(key, value);}@Overridepublic void evict(Object key) {// 同时清除两级缓存level1.evict(key);level2.evict(key);}@Overridepublic void clear() {level1.clear();level2.clear();}}// 空缓存实现(容错)static class NoOpCache implements Cache {// 实现基础的Cache方法,返回空值}
}
4. 业务层使用
@Service
public class ProductService {@Cacheable(value = "products", key = "#id")public Product getProduct(Long id) {// 数据库查询逻辑return productRepository.findById(id).orElseThrow(() -> new NotFoundException("Product not found"));}@CacheEvict(value = "products", key = "#product.id")public void updateProduct(Product product) {productRepository.save(product);}
}
5. 配置说明(application.yml)
spring:cache:multi-level:level1:ttl: 30s    # 本地缓存时间max-size: 1000level2:ttl: 5m     # Redis缓存时间redis:host: redis-cluster.prodport: 6379timeout: 2000ms

关键实现要点

  1. 缓存层级策略
Client Level1 Level2 DB 查询缓存 命中返回 查询二级缓存 返回结果 返回结果 查询数据库 返回数据 回填数据 返回数据 alt [二级缓存未命中] alt [未命中] Client Level1 Level2 DB
  1. 一致性保障
  • 写操作:同时清除两级缓存(@CacheEvict​)
  • 读操作:二级缓存命中后自动回填一级缓存
  • TTL策略:一级缓存TTL(30s) < 二级缓存TTL(5m)
  1. 性能优化
  • 本地缓存:使用Caffeine高性能缓存库
  • 异步回填:可扩展为异步加载(需自定义CacheLoader)
  • 批量操作:支持@Cacheable的批量查询优化

扩展建议

  1. 缓存预热
@PostConstruct
public void preloadHotData() {// 加载热点数据到缓存hotProducts.forEach(product -> cacheManager.getCache("products").put(product.getId(), product));
}
  1. 监控集成
@Bean
public MeterRegistryCustomizer<MeterRegistry> cacheMetrics() {return registry -> {CaffeineCacheManager caffeine = context.getBean(CaffeineCacheManager.class);RedisCacheManager redis = context.getBean(RedisCacheManager.class);// 注册Caffeine监控CacheMetrics.monitor(registry, caffeine, "level1");// 注册Redis监控CacheMetrics.monitor(registry, redis, "level2");};
}
  1. 防雪崩策略
// 在MultiLevelCache.get方法中添加
ValueWrapper get(Object key) {try {// 添加分布式锁检查if (lockManager.tryLock(key)) {// 实际查询逻辑}} finally {lockManager.unlock(key);}
}

相关文章:

基于Spring Boot的多级缓存架构实现

基于Spring Boot的多级缓存架构实现 以下是一个基于Spring Boot的多级缓存架构实现示例 多级缓存架构实现方案 1. 依赖配置&#xff08;pom.xml&#xff09; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-star…...

为什么DDPG需要目标网络而A2C不需要?

在强化学习中&#xff0c;DDPG需要目标网络而A2C不需要的主要原因在于算法架构、更新方式和目标稳定性需求的差异&#xff1a; Q值估计的稳定性需求不同 DDPG的Critic网络需要估计状态-动作值函数 Q ( s , a ) Q(s,a) Q(s,a)&#xff0c;其目标值的计算涉及下一个状态的最大Q值…...

蓝桥杯 C++ b组 统计子矩阵深度解析

题目大意&#xff1a;给定一个 NM 的矩阵 A&#xff0c;请你统计有多少个子矩阵 (最小11&#xff0c;最大NM) 满足子矩阵中所有数的和不超过给定的整数 K&#xff1f; 前言&#xff1a;这题很容易想到二维前缀和优化&#xff0c;然后枚举子矩阵&#xff0c;但这样时间复杂度为…...

YOLOv12本地部署教程——42%速度提升,让高效目标检测触手可及

YOLOv12 是“你只看一次”&#xff08;You Only Look Once, YOLO&#xff09;系列的最新版本&#xff0c;于 2025 年 2 月发布。它引入了注意力机制&#xff0c;提升了检测精度&#xff0c;同时保持了高效的实时性能。在保持速度的同时&#xff0c;显著提升了检测精度。例如&am…...

每天五分钟深度学习PyTorch:向更深的卷积神经网络挑战的ResNet

本文重点 ResNet大名鼎鼎,它是由何恺明团队设计的,它获取了2015年ImageNet冠军,它很好的解决了当神经网络层数过多出现的难以训练的问题,它创造性的设计了跳跃连接的方式,使得卷积神经网络的层数出现了大幅度提升,设置可以达到上千层,可以说resnet对于网络模型的设计具…...

C++11新特性 11.基于范围的for循环

一.简介 基本概念&#xff1a; 在 C 中&#xff0c;基于范围的 for 循环&#xff08;Range-based for loop&#xff09;是一种简化容器遍历的语法糖&#xff0c;适用于所有支持 begin() 和 end() 的容器&#xff08;如 vector、map、array 等&#xff09;。以下是其核心用法和…...

Linux搜索---locate

locate locate 是 Linux 系统中用于快速查找文件和目录的命令。它并非实时遍历文件系统&#xff0c;而是通过搜索预先建立的文件数据库来定位文件。该数据库由 updatedb 程序定期&#xff08;通常是每天&#xff09;更新&#xff0c;收录了系统中所有文件的路径信息&#xff0…...

c语言笔记 一维数组与二维数组

1.一维数组和二维数组名加1代表什么意思&#xff0c;偏移多少单位&#xff1f; 方法&#xff1a;1就是以数组的元素类型的字节为单位去偏移。 先看结论再代码验证&#xff1a; 一维数组名&#xff0b;1表示加一个整型单位的偏移量&#xff0c;也可以这么理解1就是以数组的元…...

认识Event Loop【1】

前言 这应该是一个系列文章&#xff0c;因为我觉得Event Loop&#xff08;事件循环&#xff09;是一件很抽象也很重要的一个机制。eventloop这个知识点处于非常杂糅的位置&#xff0c;和很多其他知识&#xff0c;如运行时、浏览器、渲染流程、数据结构、线程等等&#xff0c;也…...

《Linux栈破坏了,如何还原》

【栈破坏导读】栈破坏有了解过吗&#xff1f;何为栈破坏&#xff0c;栈破坏了&#xff0c;程序会立刻引发崩溃&#xff0c;我们通过gdb去调试coredump&#xff0c;栈被破坏的栈帧是没法被恢复的&#xff0c;这也给我们调试程序带来很大的困难&#xff0c;那如何还原栈破坏的第一…...

环形链表问题的探究与代码实现

在数据结构与算法的学习中&#xff0c;环形链表是一个经典的问题。它不仅考察对链表这种数据结构的理解&#xff0c;还涉及到指针操作和逻辑推理。本文将结合代码和图文&#xff0c;深入分析如何判断链表中是否有环以及如何找到环的入口点。 目录 一、判断链表中是否有环 …...

【CSS3】筑基篇

目录 复合选择器后代选择器子选择器并集选择器交集选择器伪类选择器 CSS 三大特性继承性层叠性优先级 背景属性背景色背景图背景图平铺方式背景图位置背景图缩放背景图固定背景复合属性 显示模式显示模式块级元素行内元素行内块元素 转换显示模式 结构伪类选择器结构伪类选择器…...

React:类组件(上)

kerwin老师我来了 类组件的创建 class组件&#xff0c;js里的类命名首字符大写&#xff0c;类里面包括构造函数&#xff0c;方法 组件类要继承React.Component才有效 必须包含render方法 import React from react class App extends React.Component{render() {return <…...

开启mysql远程登录

目录 前言开启步骤 前言 为了安全考虑&#xff0c;mysql默认不允许远程登录&#xff0c;需要我们自己开启。当然在远程登录之前mysql的端口也要开放。下面是mysql开启远程登录的步骤。 开启步骤 本地登录mysql mysql -u root -p然后输入登录密码 给登录账号授权 GRANT AL…...

Eclipse 查看 JAVA SE 23 官方API 源代码

第一步&#xff1a;下载 JAVA SE 23 官方API 源代码 JavaSE23API源代码资源-CSDN文库 &#xff08;或者到open jdk网站JDK Builds from Oracle:&#xff09;下载https://download.java.net/java/GA/jdk23.0.2/6da2a6609d6e406f85c491fcb119101b/7/GPL/openjdk-23.0.2_windows-…...

Spring Cloud之注册中心之Nacos的使用

目录 Naacos 服务注册/服务发现 引⼊Spring Cloud Alibaba依赖 引入Nacos依赖 引入Load Balance依赖 配置Nacos地址 服务端调用 启动服务 Naacos Nacos是Spring Cloud Alibaba的组件, Spring Cloud Alibaba遵循Spring Cloud中定义的服务注册, 服务发现规范. 因此使⽤Na…...

字符串相乘——力扣

给定两个以字符串形式表示的非负整数 num1 和 num2&#xff0c;返回 num1 和 num2 的乘积&#xff0c;它们的乘积也表示为字符串形式。 注意&#xff1a;不能使用任何内置的 BigInteger 库或直接将输入转换为整数。 示例 1: 输入: num1 "2", num2 "3" …...

机试准备第13天

第一题是模拟出入栈游戏。 #include <stdio.h> #include <stack> #include <iostream> using namespace std; int main() {string str;while(getline(cin, str)){stack<char> stk;int j 0;//扫描出栈序列strfor(char i a;i<z;i){stk.push(i);//每…...

基于OpenCV的车牌识别系统(源码+论文+部署教程)

运行环境 基于OpenCV的车牌识别系统运行环境如下&#xff1a; • Python: ≥ 3.5 • OpenCV: ≥ 4.0 • IDE工具&#xff1a;Visual Studio Code&#xff08;可自行选择&#xff09; • 技术栈&#xff1a;Python OpenCV Tkinte 主要功能 基于OpenCV的车牌识别系统主要…...

MySQL:CRUD(增删查改)

目录 一、准备工作 二、Create 新增 1、语法 2、单行数据全列插入 3、单行数据指定列插入 4、多行数据指定列插入 5、多行数据全列插入 三、Retrieve 检索 1、语法 2、全列查询 3、指定列查询 4、查询字段为表达式 &#xff08;1&#xff09;常量表达式 &…...

德鲁伊连接池

德鲁伊连接池&#xff08;Druid Connection Pool&#xff09;是一个开源的Java数据库连接池项目&#xff0c;用于提高数据库连接的性能和可靠性。德鲁伊连接池通过复用数据库连接、定时验证连接的可用性、自动回收空闲连接等机制&#xff0c;有效减少了数据库连接的创建和销毁开…...

【git】【网络】【项目配置运行】HTTP 协议的微型简易 Web 服务器---tinyEasyMuduoWebServer

【git】【网络】【项目配置运行】HTTP 协议的微型简易 Web 服务器—tinyEasyMuduoWebServer csdn项目&#xff1a; 原文链接&#xff1a;https://blog.csdn.net/weixin_45178775/article/details/122257814 github链接&#xff1a;https://github.com/wyewyewye/tinyEasyMuduo…...

每周一个网络安全相关工具——MetaSpLoit

一、Metasploit简介 Metasploit&#xff08;MSF&#xff09;是一款开源渗透测试框架&#xff0c;集成了漏洞利用、Payload生成、后渗透模块等功能&#xff0c;支持多种操作系统和硬件平台。其模块化设计&#xff08;如exploits、auxiliary、payloads等&#xff09;使其成为全球…...

Python入门———条件、循环

目录 语句 顺序语句 条件语句 缩进和代码块 判断年份是否是闰年 空语句 pass 循环 while 循环 求5的阶乘&#xff1a; 求1&#xff01;2&#xff01;3&#xff01;4&#xff01;5&#xff01; for循环 打印1-10 打印2&#xff0c;4&#xff0c;6&#xff0c;8&#x…...

InDraw6.2.3 | 甾体、核苷、黄酮类化合物实现简称命名

导语 当化学家对着屏幕输入"2-amino-1,9-dihydro-6H-purin-6-one"时&#xff0c;隔壁生物学家可能正在搜索"鸟嘌呤"&#xff1b;这种命名差异如同"火星文"与"地球语"的碰撞。现在&#xff0c;鹰谷InDraw 6.2.3版带着53种多环化合物的…...

Linux中的TCP编程接口基本使用

TCP编程接口基本使用 本篇介绍 在UDP编程接口基本使用已经介绍过UDP编程相关的接口&#xff0c;本篇开始介绍TCP编程相关的接口。有了UDP编程的基础&#xff0c;理解TCP相关的接口会更加容易&#xff0c;下面将按照两个方向使用TCP编程接口&#xff1a; 基本使用TCP编程接口…...

系统部署【信创名录】及其查询地址

一、信创类型 &#xff08;一&#xff09;服务器&#xff1a; 1.华为云 2.腾讯云 3.阿里云 &#xff08;二&#xff09;中央处理器&#xff08;CPU&#xff09;&#xff1a; 1.海思&#xff0c;鲲鹏920服务器 &#xff08;三&#xff09;中间件 1.人大金仓 &#xff0…...

JavaWeb后端基础(7)AOP

AOP是Spring框架的核心之一&#xff0c;那什么是AOP&#xff1f;AOP&#xff1a;Aspect Oriented Programming&#xff08;面向切面编程、面向方面编程&#xff09;&#xff0c;其实说白了&#xff0c;面向切面编程就是面向特定方法编程。AOP是一种思想&#xff0c;而在Spring框…...

Python 中多种方式获取屏幕的 DPI值

在 Python 中&#xff0c;可以通过多种方式获取屏幕的 DPI&#xff08;每英寸点数&#xff09;。以下是几种常见的方法&#xff1a; 方法 1&#xff1a;使用 tkinter 模块 tkinter 是 Python 的标准 GUI 库&#xff0c;可以通过它获取屏幕的 DPI。 import tkinter as tkdef …...

高效数据分析实战指南:Python零基础入门

高效数据分析实战指南 —— 以Python为基石&#xff0c;构建您的数据分析核心竞争力 大家好&#xff0c;我是kakaZhui&#xff0c;从事数据、人工智能算法多年&#xff0c;精通Python数据分析、挖掘以及各种深度学习算法。一直以来&#xff0c;我都发现身边有很多在传统行业从…...