SpringCache小记

news2025/3/25 20:17:43

Spring Cache 小记

官方文档:https://springdoc.cn/spring-cache-tutorial/

基础知识

常用注解

@EnableCaching:开启缓存功能,一般放在启动类上。

  1. @Cacheable:表示该方法支持缓存。当调用被注解的方法时,如果对应的键已经存在缓存,则不再执行方法体,而从缓存中直接返回。当方法返回 null 时,将不进行缓存操作。(一般用于查询方法上)

  2. @CachePut:表示执行该方法后,其值将作为最新结果更新到缓存中,每次都会执行该方法。(一般用于新增方法上)

  3. @CacheEvict:表示执行该方法后,将触发缓存清除操作。(一般用于更新或删除方法上)

  4. @Caching:用于组合前三个注解,例如:

    @Caching(cacheable = @Cacheable("CacheConstant.GET_USER"),
             evict = {@CacheEvict("CacheConstant.GET_DYNAMIC", allEntries = true)}
    public User find(Integer id) {
        return null;
    }
    // 使用参数 allEntries 与要清空的缓存结合使用;这将清除缓存 CacheConstant.GET_DYNAMIC 中的所有条目。
    // cacheable -- @Cacheable
    // put       -- @CachePut
    // evict     -- @CacheEvict
    

常用注解属性

  1. value/cacheNames:缓存名称(必填),指定缓存的命名空间;

  2. key:用于设置在命名空间中的缓存 key 值,默认使用方法参数值,也可以使用 SpEL 表达式定义;

  3. keyGenerator:缓存 Key 的生成策略,它和 key 属性互斥使用(只能二选一)

  4. unless:条件符合则不缓存;

    使用 unless 时可以在调用的方法获取到结果之后再进行判断(如 #result == null,表示如果结果为 nu11 时不缓存)

  5. condition:条件符合则缓存;

  6. cacheManager:指定使用的缓存管理器;

  7. cacheResolver:作用和 cacheManager 属性一样(只能二选一)

  8. sync:是否使用同步模式。若使用同步模式,在多个线程同时对一个 key 进行 load 时,其他线程将被阻塞。默认值是 false

缓存同步模式:

sync 开启或关闭,在 CacheLoadingCache 中的表现是不一致的:

  • Cache 中,sync 表示是否需要所有线程同步等待
  • LoadingCache 中,sync 表示在读取 不存在/已驱逐 的 key 时,是否执行被注解方法

清理全部缓存

通过 allEntriesbeforeInvocation 属性可以来清除全部缓存数据,

  1. 不过 allEntries 是方法调用清理,
  2. beforeInvocation 是方法调用清理。

SpEL表达式

SpEL 表达式的语法

img

Spring Cache 可用的变量

img

Caffeine 缓存设置及代码实践

1. 引入依赖

				<!-- 引入Caffeine缓存依赖 -->
			  <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
        </dependency>

注释:选择使用 Caffeine 作为缓存依赖,是因为它是一款性能卓越的本地缓存库,具有快速、高效和可配置的特点。

2. 编写配置类

@Configuration
@EnableCaching
public class CacheConfig {

    /**
     * 配置Caffeine缓存管理器
     */
    @Bean
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setCaffeine(Caffeine.newBuilder()
            // 设置缓存过期时间为30分钟
            .expireAfterWrite(30, TimeUnit.MINUTES)
            // 设置最大缓存条目数
            .maximumSize(1000)
            .recordStats()
        );
        return cacheManager;
    }

}

3. 编写字典业务类

@Service
public class DictionaryService {

    @Resource
    private DocumentExpiredMapper documentExpiredMapper;

    /**
     * 通过@Cacheable注解将字典数据存入缓存
     * @param dictionaryType 字典类型
     * @return 字典数据的HashMap
     */
    @Cacheable(value = "dictionaryCache", key = "#dictionaryType")
    public HashMap<String, String> getDict(String dictionaryType) {
        List<DictDTO> dictList = documentExpiredMapper.getDict(dictionaryType);
        HashMap<String, String> dictMap = new HashMap<>(16);
        for (DictDTO dictDTO : dictList) {
            dictMap.put(dictDTO.getDictValue(), dictDTO.getDictName());
        }
        return dictMap;
    }

}
注解解析

@Cacheable 是 Spring 框架中用于声明一个方法要被缓存处理的注解。在上面这段代码中,它的用法是为 getDict 方法添加了缓存的支持。

具体到这个注解的属性解释如下:

  • value:指定缓存的名称,可以理解为给缓存起一个名字,这样你可以在不同地方使用相同名字的缓存。在你的例子中,缓存的名称是 “dictionaryCache”。
  • key:指定缓存的键。缓存的键决定了缓存的唯一性。在你的例子中,"#dictionaryType" 表示缓存的键是方法的参数 dictionaryType 的值。这样就能够通过不同的 dictionaryType 值来区分不同的缓存数据。

综合起来,@Cacheable(value = "dictionaryCache", key = "#dictionaryType") 的含义是:

  • 这个方法的执行结果将会被缓存起来。
  • 缓存的名称是 “dictionaryCache”。
  • 缓存的键是方法的参数 dictionaryType 的值。

流程解析

当这个方法被调用时,Spring 会先检查缓存中是否已经存在了相同键的缓存数据,如果存在就直接返回缓存的结果,而不执行方法体;如果不存在,就执行方法体,并将方法的结果缓存起来,以备后续相同参数的方法调用直接使用缓存数据,提高执行效率。这样,对于相同的 dictionaryType 参数,方法的执行结果只需要计算一次,之后就可以直接从缓存中获取,避免了重复计算。

4. 编写抽象字典转换器

public abstract class AbstractDictConverter implements Converter<String> {

	/**
	 * 获取字典类型
	 * 使用protected修饰符可以将方法或变量限制在同一包中的类和子类中访问。
	 * @return
	 */
	protected abstract String getDictType();

	@Override
	public Class<?> supportJavaTypeKey() {
		return String.class;
	}

	@Override
	public CellDataTypeEnum supportExcelTypeKey() {
		return CellDataTypeEnum.STRING;
	}

	@Override
	public String convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
		return cellData.getStringValue();
	}

	@Override
	public WriteCellData<?> convertToExcelData(WriteConverterContext<String> context) {
		DictionaryService bean = SpringUtil.getBean(DictionaryService.class);
		HashMap<String, String> dictMap = bean.getDict(getDictType());
		String convertedValue = dictMap.get(context.getValue());
		if (convertedValue != null) {
			return new WriteCellData<>(convertedValue);
		} else {
			return new WriteCellData<>(context.getValue());
		}
	}

}

注意事项:

  1. 因为这个转换器是一个 抽象类,而且通常是 手动 new 出来的,而不是由 Spring 容器管理的,所以无法自动注入 @Autowired 依赖。
  2. 因此,需要使用 SpringUtil.getBean() 手动获取 DictionaryService

5. 继承使用

第一个转换器:

public class AlertTypeConvert extends AbstractDictConverter {

	@Override
	protected String getDictType() {
		return ALERT_TYPE;
	}

}

第二个转换器:

public class DocumentDictConverter extends AbstractDictConverter {

	@Override
	protected String getDictType() {
		return CERTIFICATE;
	}

}

注意事项

💡 注意:在线上环境可能会遇到问题,比如测试环境正常运行,但在生产环境中无法进行字典转换,可能导致转换失败。为了解决这个问题,我们可以考虑使用自定义的静态变量 HashMap 来实现该功能,确保字典数据在各个环境中都能正确加载。

其他实现方式阅读:

文件导出之自定义字典映射转换器

学习参考

  • Java 本地缓存之王Caffeine - 掘金 (juejin.cn)

  • 程序员必备的Spring集成缓存知识:深入浅出的教程分享 - 掘金 (juejin.cn)

  • SpringBoot缓存注解@Cacheable之自定义key策略及缓存失效时间指定 - 掘金 (juejin.cn)

  • 深入浅出@Cacheable-CSDN博客

  • Spring之缓存注解@Cacheable-CSDN博客

  • https://juejin.cn/post/6844904094545477640?searchId=202407011552082E85C3497B3684283B5D

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

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

相关文章

Web-Machine-N7靶机通关攻略

获取靶机ip arp-scan -l 端口扫描 nmap xxxx 访问80端口发现没用 扫描目录 gobuster dir -u http:/192.168.117.160 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium,txt -x php,html,txt ,zip 打开exploit.html 点击F12&#xff0c;修改localhost为靶机ip&#…

第十五次CCF-CSP认证(含C++源码)

第十五次CCF-CSP认证 小明上学满分思路 数据中心满分思路 小明放学满分题解 小明上学 题目链接 满分思路 其实题目看着长&#xff0c;但是做起来是非常好写的&#xff0c;其实主要原因在于&#xff0c;他的红绿灯的变化规律是一定的&#xff0c;而且小明路上的每次红绿灯情况…

Java-servlet(七)详细讲解Servlet注解

Java-servlet&#xff08;七&#xff09;详细讲解Servlet注解 前言一、注解的基本概念二、Override 注解2.1 作用与优势2.2 示例代码 三、Target 注解3.1 定义与用途3.2 示例代码 四、WebServlet 注解4.1 作用4.2 示例代码 五、反射与注解5.1 反射的概念5.2 注解与反射的结合使…

SQLark 实战 | 如何通过对象名和 DDL 快速搜索数据库对象

在数据库运维管理、应用开发和问题定位时&#xff0c;常常需要搜索相关的数据库对象。本文将为你介绍如何使用 SQLark 的搜索功能&#xff0c;实现对数据库对象的快速查找与定位。 &#x1f449; 前往 SQLark 官网&#xff1a;www.sqlark.com 下载全功能免费版。 通过对象名称搜…

C/S模型-TCP

下图是基于TCP协议的客户端/服务器程序的一般流程&#xff1a; TCP协议通讯流程 服务器调用socket()、bind()、listen()完成初始化后&#xff0c;调用accept()阻塞等待&#xff0c;处于监听端口的状态&#xff0c;客户端调用socket()初始化后&#xff0c;调用connect()发出SY…

51c自动驾驶~合集24

我自己的原文哦~ https://blog.51cto.com/whaosoft/11926510 #DriveArena 上海AI Lab又放大招&#xff1a;首个高保真闭环生成仿真平台 仓库链接&#xff1a;https://github.com/PJLab-ADG/DriveArena 项目链接&#xff1a;https://pjlab-adg.github.io/DriveArena/ D…

19.哈希表的实现

1.哈希的概念 哈希(hash)⼜称散列&#xff0c;是⼀种组织数据的⽅式。从译名来看&#xff0c;有散乱排列的意思。本质就是通过哈希函数把关键字Key跟存储位置建⽴⼀个映射关系&#xff0c;查找时通过这个哈希函数计算出Key存储的位置&#xff0c;进⾏快速查找。 1.2.直接定址法…

【PCB工艺】晶体管的发展历史

晶体管被认为是20世纪最伟大的发明之一&#xff0c;因为没有晶体管就不会有现代电脑、手机或平板​​&#xff0c;你也无法阅读到这里的内容&#xff0c;因为不存在网络。 ——本文纯粹出于对过往奋斗在这个领域中科学家的缅怀。科学家有太多宝贵的思想和经验值得我们认真总结和…

通向AGI的未来之路!首篇2D/视频/3D/4D统一生成框架全景综述(港科大中山等)

文章链接&#xff1a; https://arxiv.org/pdf/2503.04641 摘要 理解并复现现实世界是人工通用智能&#xff08;AGI&#xff09;研究中的一个关键挑战。为实现这一目标&#xff0c;许多现有方法&#xff08;例如世界模型&#xff09;旨在捕捉支配物理世界的基本原理&#xff0…

【亚马逊云科技】大模型选型实战(挑选和测评对比最适合业务的大模型)

文章目录 前言1、实验内容2、手册内容 一、环境准备二、Prompt 实战与模型配置2.1 基于 Amazon Bedrock 对比测试不同模型的逻辑推理效果2.2 基于 Amazon Bedrock 对比测试不同模型知识问答能力2.3 Prompt 实战结果分析 三、基于 Amazon Bedrock Evaluations 进行模型评测与自动…

调用feapder作为子程序时setting.py文件不起作用

feaper 官方文档地址&#xff1a; 简介及安装 - feapder官方文档|feapder-document 问题&#xff1a; 在最近的开发中需要调用feapder作为主程序调用的子程序时发现自动入库时无法入库&#xff0c;通过查看日志信息发现连接数据库时被拒绝连接了&#xff0c;但是我的setting.p…

【从零开始学习计算机科学】软件测试(九)Web系统测试 与 数据库测试

【从零开始学习计算机科学】软件测试(九)Web系统测试 与 数据库测试 Web系统测试Web系统基本组成Web系统的服务器端应用特点Web系统测试的分类Web应用系统测试的实施功能测试链接测试表单测试性能测试连接速度测试负载测试压力测试可用性测试导航测试图形测试内容测试表格测试…

G-Star 校园开发者计划·黑科大|开源第一课之 Git 入门

万事开源先修 Git。Git 是当下主流的分布式版本控制工具&#xff0c;在软件开发、文档管理等方面用处极大。它能自动记录文件改动&#xff0c;简化合并流程&#xff0c;还特别适合多人协作开发。学会 Git&#xff0c;就相当于掌握了一把通往开源世界的钥匙&#xff0c;以后参与…

5.0 VisionPro调用USB相机的方法与步骤说明(一)

本文介绍如何在C#中调用visionPro以处理USB相机采集到的图片。示例如下: 主要思路如下: 1. 使用AForge来打开以及采集usb相机照片。 usb相机处于一直运行状态。每隔100ms采集一次照片。且触发一次事件。 public void Start() { this.videoSourcePlayer.Stop(); …

微信小程序计算属性与监听器:miniprogram-computed

小程序框架没有提供计算属性相关的 api &#xff0c;但是官方为开发者提供了拓展工具库 miniprogram-computed。 该工具库提供了两个功能&#xff1a; 计算属性 computed监听器 watch 一、安装 miniprogram-computed 在项目的根目录下&#xff0c;使用如下命令&#xff0c;…

强大的AI网站推荐(第二集)—— V0.dev

网站&#xff1a;V0.dev 号称&#xff1a;前端开发神器&#xff0c;专为开发人员和设计师设计&#xff0c;能够使用 AI 生成 React 代码 博主评价&#xff1a;生成的UI效果太强大了&#xff0c;适合需要快速创建UI原型的设计师和开发者 推荐指数&#xff1a;&#x1f31f;&…

整理和总结微信小程序的高频知识点

前言 近期萌生了一些想法&#xff0c;感觉可以做一个小程序作为产出。 但小程序做得比较少&#xff0c;因此边做边复习。整理和总结了一些高频知识点和大家一起分享。 一、模板和组件 1.1模板&#xff08;Template&#xff09; 优势 简单灵活&#xff1a;模板定义和使用都较…

vue中js简单创建一个事件中心/中间件/eventBus

vue中js简单创建一个事件中心/中间件/eventBus 目录结构如下&#xff1a; eventBus.js class eventBus {constructor() {this.events {};}// 监听事件on(event, callback) {if (!this.events[event]) {this.events[event] [];}this.events[event].push(callback);}// 发射…

# [RPA] 使用八爪鱼进行高效网页数据采集

在许多行业中&#xff0c;数据是核心资产。然而&#xff0c;虽然许多网站的文本内容可以免费访问&#xff0c;但手动一条一条采集&#xff0c;不仅耗时耗力&#xff0c;还容易出错。这种情况下&#xff0c;使用自动化工具来提高采集效率就显得尤为重要。本文将介绍 八爪鱼 这一…

K8S学习之基础三十七:prometheus监控node资源

Prometheus v2.2.1 ​ 编写yaml文件&#xff0c;包含创建ns、configmap、deployment、service # 创建monitoring空间 vi prometheus-ns.yaml apiVersion: v1 kind: Namespace metadata:name: monitor-sa# 创建SA并绑定权限 kubectl create serviceaccount monitor -n monito…