Spring 之 @Cacheable 缓存使用教程

1、@Cacheable 指定使用缓存

定义个 Controller ,在方法上加上注解 @Cacheable,配置要使用哪些缓存,比如 myMapCache 表示一级缓存是 Map,myRedisCache 表示二级缓存是 Redis。并配置缓存 key。 key 由 SPEL 表达式组成,Spring 可以动态解析生成缓存 key。

提示:myMapCache、myRedisCache 均为注入 Spring 缓存的名称

@RestController
public class CachingAnnoController {@Cacheable(cacheNames = {"myMapCache","myRedisCache"},key = "'test_'+#key")@RequestMapping("/cachingAnno")public String cachingAnno(String key,String value){System.out.println("查询数据库值 = " + value);return "value";}
}

2、@EnableCaching 开启缓存功能

用过 @Cacheable 注解的都知道,要开启缓存功能必须通过 @EnableCaching 注解。代码如下:

@ComponentScan(value = "com.gwm")
@Configuration
@EnableCaching
public class SpringConfig {}

3、引入具体要使用的缓存—实现 Cache 接口

上述 @EnableCaching、@Cacheable 都是 Spring 提供的基本缓存框架,而具体的缓存需要自己引入。比如现在自己定义两个缓存:MyMapCache 类 、MyRedisCache 类。然后实现接口方法。

Spring 提供 Cache 作为标准化接口,具体的实现 Spring 不管,你自己去实现。但是 Spring 也是有几个默认实现的,比如:CaffeineCache、EhCacheCache、ConcurrentMapCache、JCacheCache 等。

public class MyMapCache implements Cache {public static final Map<Object, Object> map = new ConcurrentHashMap<>();private String cacheName;public MyMapCache(String cacheName) {this.cacheName = cacheName;}@Overridepublic String getName() {return cacheName;}@Overridepublic Object getNativeCache() {return null;}@Overridepublic ValueWrapper get(Object key) {System.out.println(">>>>>>我是 MyMapCache 缓存中的 get() 方法");Object o = map.get(key);if (Objects.nonNull(o)) {return new SimpleValueWrapper(o);}return null;}@Overridepublic <T> T get(Object key, Class<T> type) {return (T)map.get(key);}@Overridepublic <T> T get(Object key, Callable<T> valueLoader) {return (T)map.get(key);}@Overridepublic void put(Object key, Object value) {System.out.println(">>>>>>我是 MyMapCache 缓存中的 put() 方法");map.put(key, value);}@Overridepublic void evict(Object key) {map.remove(key);}@Overridepublic void clear() {map.clear();}
}

MyRedisCache 类实现,代码如下:

public class MyRedisCache implements Cache {private String cacheName;private RedisTemplate<Object,Object> redisTemplate;public MyRedisCache(String cacheName, RedisTemplate<Object, Object> redisTemplate) {this.cacheName = cacheName;this.redisTemplate = redisTemplate;}@Overridepublic String getName() {return cacheName;}@Overridepublic Object getNativeCache() {return this;}@Overridepublic ValueWrapper get(Object key) {System.out.println(">>>>>>我是 MyRedisCache 缓存中的 get() 方法");Object o = redisTemplate.opsForValue().get(key);if (Objects.nonNull(o)) {return new SimpleValueWrapper(o);}return null;}@Overridepublic <T> T get(Object key, Class<T> type) {return null;}@Overridepublic <T> T get(Object key, Callable<T> valueLoader) {return null;}@Overridepublic void put(Object key, Object value) {System.out.println(">>>>>>我是 MyRedisCache 缓存中的 put() 方法");redisTemplate.opsForValue().set(key,value);redisTemplate.expire(key, Duration.ofMillis(3000));}@Overridepublic void evict(Object key) {redisTemplate.delete(key);}@Overridepublic void clear() {redisTemplate.execute((RedisCallback<Object>) conn->{// 清空所有缓存数据,要格外注意这个操作,很危险conn.flushDb();return ">>>>>>flush db success!";});}
}

4、缓存管理类—实现 CacheManager 接口

自定义缓存定义完之后,光摆在这里肯定是不能起作用的,还需要借助 Spring 标准化接口 CacheManager 类来把缓存加入到缓存切面逻辑中。

比如实现 MyMapCache 缓存管理类 MyMapCacheManager,代码如下:

public class MyMapCacheManager implements CacheManager {@Overridepublic Cache getCache(String name) {return new MyMapCache(name);}@Overridepublic Collection<String> getCacheNames() {return Arrays.asList("myMapCache");}
}

实现 MyRedisCache 缓存管理类 MyRedisCacheManager,代码如下:

public class MyRedisCacheManager implements CacheManager {@Overridepublic Cache getCache(String name) {return new MyRedisCache(name,redisTemplate);}@Overridepublic Collection<String> getCacheNames() {return Arrays.asList("myRedisCache");}
}

然后在配置入口类中通过 @Bean 引用具体的缓存。代码如下:

@Configuration
public class MyRedisMainConfig {@Resourceprivate RedisTemplate<Object,Object> redisTemplate;@Beanpublic MyMapCache myMapCache() {MyMapCache myMapCache = new MyMapCache("myMapCache");return myMapCache;}@Beanpublic MyRedisCache myRedisCache() {MyRedisCache myRedisCache = new MyRedisCache("myRedisCache",redisTemplate);return myRedisCache;}@Beanpublic MyRedisCacheManager cacheManager() {MyRedisCacheManager redisCacheManager = new MyRedisCacheManager();return redisCacheManager;}// @Bean public MyMapCacheManager cacheManager() {MyRedisCacheManager redisCacheManager = new MyRedisCacheManager();return redisCacheManager;}}

但是发现使用具体的管理类引入缓存,只能引入对应的缓存。比如 MyRedisCacheManager 管理类就只能引入 MyRedisCache 缓存,不能引入 MyMapCache。所以这是个弊端。如果想要使用双缓存,那怎么办呢?

5、双缓存使用—实现 AbstractCacheManager 抽象类

该抽象类提供 loadCaches() 方法,可以获取到所有 Cache 接口实现类。所以这里能够获取到所有缓存。那么肯定是可以使用双缓存。比如 MySimpleCacheManager 类实现,代码如下:

public class MySimpleCacheManager extends AbstractCacheManager implements ApplicationContextAware {private static final List<Cache> list = new ArrayList<>();private ApplicationContext context;/*** 直接实现 AbstractCacheManager 抽象类的钩子方法,该类已经写好模版方法* 当执行的时候,如果 MyGuavaCacheManager 管理类 @Bean 的话,就会勾到这个方法逻辑* @return*/@Overrideprotected Collection<? extends Cache> loadCaches() {return list;}@Overridepublic void afterPropertiesSet() {Map<String, Cache> beansOfType = context.getBeansOfType(Cache.class);list.addAll(beansOfType.values());}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException this.context = applicationContext;}
}

然后再配置入口类,代码如下:

@Configuration
public class MyRedisMainConfig {@Resourceprivate RedisTemplate<Object,Object> redisTemplate;@Beanpublic MyMapCache myMapCache() {MyMapCache myMapCache = new MyMapCache("myMapCache");return myMapCache;}@Beanpublic MyRedisCache myRedisCache() {MyRedisCache myRedisCache = new MyRedisCache("myRedisCache",redisTemplate);return myRedisCache;}@Beanpublic MySimpleCacheManager cacheManager(@Qualifier("myMapCache") MyMapCache myMapCache,@Qualifier("myRedisCache") MyRedisCache myRedisCache,@Qualifier("myGuavaCache") MyGuavaCache myGuavaCache) {SimpleCacheManager simpleCacheManager = new SimpleCacheManager();simpleCacheManager.setCaches(Arrays.asList(myMapCache,myRedisCache,myGuavaCache));return simpleCacheManager;}
}

最终通过注入一个缓存管理类 MySimpleCacheManager 就可以使用到三个缓存。美滋滋。最终要使用,就通过 @Cacheable(cacheNames = {“myMapCache”,“myRedisCache”},key = “‘test_’+#key”) 即可使用 myMapCache、myRedisCache 缓存。如果还需要使用 myGuavaCache,直接往数组中添加即可。

6、 RedisCacheManager 内置类

在使用 Redis 缓存时,Spring 早已对其包装完成,只需要引入 spring-data-redis 包即可。我们不需要写 MyRedisCacheManager 类,Spring 早就提供 RedisCacheManager 类管理 Redis 缓存 。所以你只需能够连接好 Redis 。然后通过 @Bean 将 RedisCacheManager 类注入即可使用 Redis 缓存。

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

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

相关文章

异常检测 | MATLAB实现BiLSTM(双向长短期记忆神经网络)数据异常检测

异常检测 | MATLAB实现BiLSTM(双向长短期记忆神经网络)数据异常检测 目录 异常检测 | MATLAB实现BiLSTM(双向长短期记忆神经网络)数据异常检测效果一览基本介绍模型准备模型设计参考资料效果一览 基本介绍 训练一个双向 LSTM 自动编码器来检测机器是否正常工作。 自动编码器接受…

CleanMyMac X2024最新版本软件实用性测评

信大多数MAC用户都较为了解&#xff0c;Mac虽然有着许多亮点的性能&#xff0c;但是让用户叫苦不迭的还其硬盘空间小的特色&#xff0c;至于很多人因为文件堆积以及软件缓存等&#xff0c;造成系统空间内存不够使用的情况。于是清理工具就成为了大多数MAC用户使用频率较高的实用…

二十一章网络通信

计算机网络实现了多台计算机间的互联&#xff0c;使得它们彼此之间能够进行数据交流。网络应用程序就是在已连接的不同计算机上运行的程序&#xff0c;这些程序借助于网络协议&#xff0c;相互之间可以交换数据。编写网络应用程序前&#xff0c;首先必须明确所要使用的网络协议…

数据采集工具的大全【都是免费值得收藏】

数据是推动业务成功的关键之一。为了获取准确、全面的信息&#xff0c;数据采集成为了许多企业和个人的必备工作。本文将专注于数据采集工具&#xff0c;探讨其在全网和指定网站采集方面的优势&#xff0c;为大家提供对比分析&#xff0c;以帮助大家找到最适合的数据采集利器。…

算法复习——6种排序方法的简单回顾

算法复习——6种排序方法的简单回顾 常见排序方法&#xff1a;冒泡排序、选择排序、插入排序、堆排序、归并排序、快速排序的简单回顾 冒泡排序 重复“从序列右边开始比较相邻两个数字的大小,再根据结果交换两个数字的位置” 在冒泡排序中&#xff0c;第 1 轮需要比较 n - 1…

Tair(1):Tair介绍

1 介绍 ​ 在Tair出现之前的很长一段时间里&#xff0c;像redis、memcache这些知名NoSql数据库是不支持分布式的&#xff0c;在这样的背景下&#xff0c;由淘宝网自主开发并在2010.6开源的一个高性能、高扩展、高可靠分布式缓存&#xff0c;类似map的key/value结构&#xff0c…

使用单例模式+观察者模式实现参数配置实时更新

使用vector存储观察者列表 #include <iostream> #include <vector> #include <functional> #include <algorithm>// 配置参数结构体 struct MyConfigStruct {int parameter1;std::string parameter2; };class Config { public:using Observer std::f…

hive 命令行中使用 replace 和nvl2 函数报错

1.有时候在命令行的情况下使用 replace 函数时会报错 这个时候可以使用 translate 代替 2.有时候使用 nvl2() 函数的时候会报错 这个时候可以用 case when 来代替

【Spring 源码】 深入理解 Bean 定义之 BeanDefinition

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…

两数之和问题

更好的阅读体验请点击 两数之和。 题目&#xff1a;两数之和 ​ 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 ​ 你可以假设每种输入只会对应一个答案。但是&#xff…

MetricBeat监控Redis

目录 一、安装部署 二、开启Redis监控模块 三、编辑Redis配置文件 四、启动Metricbeat 五、查看监控图表 一、安装部署 metriceat的安装部署参考章节&#xff1a; 监控组件>Metricbeat安装使用&#xff0c;这里不再赘述。 二、开启Redis监控模块 进入metricbeat安装目录…

【每日一题】出租车的最大盈利

文章目录 Tag题目来源解题思路方法一&#xff1a;递归方法二&#xff1a;递归记录数组记忆化搜索方法三&#xff1a;动态规划&#xff08;递推&#xff09; 写在最后 Tag 【递归】【记忆化搜索】【动态规划】【数组】【2023-12-08】 题目来源 2008. 出租车的最大盈利 解题思路…

【EI会议征稿中】2024年第四届人工智能、自动化与高性能计算国际会议(AIAHPC 2024)

2024年第四届人工智能、自动化与高性能计算国际会议&#xff08;AIAHPC 2024&#xff09; 2024 4th International Conference on Artificial Intelligence, Automation and High Performance Computing 2024第四届人工智能、自动化与高性能计算国际会议(AIAHPC 2024)将于20…

蓝桥杯从零开始备战(Python组)---基础知识篇

第一次尝试报名蓝桥杯的Python组&#xff0c;好好备战&#xff0c;希望省赛可以拿奖&#xff01;目前是整理了一些Python的常用函数和常用内置库&#xff0c;后面可能会开始刷题&#xff0c;如果有比较需要记住的知识点&#xff0c;会再写一篇刷题篇 一、输入输出 1.输入字符…

游戏被攻击怎么办

随着科技的进步和互联网的普及&#xff0c;游戏行业也正在经历前所未有的变革。玩家们不再满足于传统的线下游戏&#xff0c;而是转向了线上游戏。然而&#xff0c;随着游戏的线上化&#xff0c;游戏安全问题也日益凸显。游戏受到攻击是游戏开发者永远的痛点&#xff0c;谈“D“…

HomeAssistant添加HACS插件并实现公网控制米家,HomeKit等智能家居

HomeAssistant添加HACS插件并实现公网控制米家&#xff0c;HomeKit等智能家居 文章目录 HomeAssistant添加HACS插件并实现公网控制米家&#xff0c;HomeKit等智能家居基本条件一、下载HACS源码二、添加HACS集成三、绑定米家设备 ​ 上文介绍了如何实现群晖Docker部署HomeAssist…

【嵌入式开发 Linux 常用命令系列 4.1 -- git push 远程分支与本地分支查看】

文章目录 概述git push 语法步骤1&#xff1a;git 远程主机名查看步骤2&#xff1a;git 远程分支名查看步骤3&#xff1a;git 本地分支名查看示例演示 概述 在日常工作中&#xff0c;将代码 git clone 本地之后&#xff0c;或者使用repo init && repo sync 之后不知道…

SQLserver截取字符串

当我们存的数据是json的时候可以全部取出在模糊查询但是有多个重复数据的时候就没办法准确的模糊出来这个时候我们就需要用的字符串截取 --创建函数create FUNCTION [dbo].[Fmax] (str varchar(50),start VARCHAR(50),length VARCHAR(50)) RETURNS varchar(max) AS BEGINDEC…

商品详情页评论和评论列表评论的排序html代码

以下是一个简单的商品详情页的 HTML 代码示例&#xff1a; <!DOCTYPE html> <html> <head><title>商品详情页</title><style>/* CSS 样式可以在这里添加 */</style> </head> <body><h1>商品详情页</h1><…

7-1 查找书籍

给定n本书的名称和定价&#xff0c;本题要求编写程序&#xff0c;查找并输出其中定价最高和最低的书的名称和定价。 输入格式: 输入第一行给出正整数n&#xff08;<10&#xff09;&#xff0c;随后给出n本书的信息。每本书在一行中给出书名&#xff0c;即长度不超过30的字…