Spring 之 @Cacheable 缓存使用教程

news/2023/6/7 1:26:03

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.exyb.cn/news/show-4554759.html

如若内容造成侵权/违法违规/事实不符,请联系郑州代理记账网进行投诉反馈,一经查实,立即删除!

相关文章

Linux鼠标回报率修改,技术编辑帮您鼠标怎么调回报率

电脑现已成为我们工作、生活和娱乐必不可少的工具了&#xff0c;在使用电脑的过程中&#xff0c;可能会遇到鼠标怎么调回报率的问题&#xff0c;如果我们遇到了鼠标怎么调回报率的情况&#xff0c;该怎么处理怎么才能解决鼠标怎么调回报率带来的困扰呢&#xff0c;对于这样的问…

Linux鼠标回报率修改,鼠标回报率修改(hidusbf)

鼠标回报率修改(hidusbf)是用来修改鼠标默认采样率的神器&#xff0c;使用后可以有效的解决各种因为软件设置问题导致的鼠标不能正常移动&#xff0c;丢帧&#xff0c;负加速(反加速)等错误。怎么用&#xff1a;(此软件在WINXP3下&#xff0c;运行正常&#xff0c;在WIN7下更加…

java.util.ConcurrentModificationException at java.util.ArrayList$Itr.next(ArrayList.java:860

问题 使用ArrayList数据结构&#xff0c; 在迭代的请求页面进行数据刷新&#xff0c; 控制台报错 java.util.ConcurrentModificationExceptionat java.util.ArrayList$Itr.next(ArrayList.java:860)at 详细问题 2022-09-27 11:18:00.135 17592-17592/com.example.electronic…

记2022年秋招经历

自我介绍求职体验求职心得 一、自我介绍 学历普通本科&#xff0c;专业是网络工程&#xff0c;在校期间学习主要的是计算机体系方面的知识&#xff0c;根据课程&#xff0c;自学过前端、后端等内容。包括前端三板斧(htmlcssjs)、常用的前端框架(bootstarp/Vue等&#xff09;&am…

tomcat JMX port 1099被占用 ,导致 项目无法启动 localhost:1099 is already in use

Error running ‘Tomcat 8.5.37’: Address localhost:1099 is already in use 解决方法: 打开cmd 输入: netstat -ano | find "1099" 查出占用 1099 的进程 输入: taskkill /F /PID 10388杀死占用的进程 再次启动tomcat , 正常运行

Lesson 3. 线性回归的手动实现(3.3 线性回归手动实现与模型局限 3.4 机器学习模型结果可信度理论与交叉验证基础)

文章目录一、线性回归手动实现与模型局限1. 线性回归的手动实现2. 线性回归模型局限3. 线性回归的决定系数二、机器学习模型结果可信度理论与交叉验证基础1. 机器学习模型结果可信度理论基础与数据集划分1.1 机器学习模型结果可信度基础理论1.2 数据集切分方法1.3 线性回归手动…

京东云给新建空间添加用户权限,并在jmr中通过linux/hadoop命令查看对应的文件信息

之前使用过亚马逊的云服务和阿里云&#xff0c;现在使用京东云&#xff0c;权限配置这一块还是有区别的&#xff0c;做个小记录&#xff0c;yi 以后忘记了就翻一翻。 1.京东云对象存储里面新建空间 2.进入访问控制 3.点击子用户下方数字 4.点击你要添加的子用户&#xff0c;并…

Jmeter性能测试(13)--常见问题及解决方法

jmeter作为一个开源的纯Java性能测试工具&#xff0c;工作中极大的方便了我们进行接口、性能测试&#xff0c;但使用过程中也遇到了很多的问题&#xff0c;下面就记录一下自己遇到的问题&#xff0c;后续会不断更新。。。 1、获取日志 在使用jmeter过程中&#xff0c;如果想获…