电子说
作者最近在开发公司项目时使用到 Redis 缓存,并在翻看前人代码时,看到了一种关于 @Cacheable 注解的自定义缓存有效期的解决方案,感觉比较实用,因此作者自己拓展完善了一番后分享给各位。
Spring 缓存常规配置
Spring Cache 框架给我们提供了 @Cacheable 注解用于缓存方法返回内容。但是 @Cacheable 注解不能定义缓存有效期。这样的话在一些需要自定义缓存有效期的场景就不太实用。
按照 Spring Cache 框架给我们提供的 RedisCacheManager 实现,只能在全局设置缓存有效期。这里给大家看一个常规的 CacheConfig 缓存配置类,代码如下,
@EnableCaching @Configuration public class CacheConfig extends CachingConfigurerSupport { ... private RedisSerializer keySerializer() { return new StringRedisSerializer(); } private RedisSerializer valueSerializer() { return new GenericFastJsonRedisSerializer(); } public static final String CACHE_PREFIX = "crowd:"; @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { // 配置序列化(解决乱码的问题) RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() //设置key为String .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer())) //设置value为自动转Json的Object .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer())) .computePrefixWith(name -> CACHE_PREFIX + name + ":") .entryTtl(Duration.ofSeconds(600)); RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(Objects.requireNonNull(redisConnectionFactory)); return new RedisCacheManager(redisCacheWriter, config); } } 这里面简单对 RedisCacheConfiguration 缓存配置做一下说明: serializeKeysWith():设置 Redis 的 key 的序列化规则。 erializeValuesWith():设置 Redis 的 value 的序列化规则。 computePrefixWith():计算 Redis 的 key 前缀。 entryTtl():全局设置 @Cacheable 注解缓存的有效期。 那么使用如上配置生成的 Redis 缓存 key 名称是什么样得嘞?这里用开源项目 crowd-admin 的 ConfigServiceImpl 类下 getValueByKey(String key) 方法举例, @Cacheable(value = "configCache", key = "#root.methodName + '_' + #root.args[0]") @Override public String getValueByKey(String key) { QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("configKey", key); Config config = getOne(wrapper); if (config == null) { return null; } return config.getConfigValue(); } 执行此方法后,Redis 中缓存 key 名称如下, crowdgetValueByKey_sys.name TTL 过期时间是 287,跟我们全局设置的 300 秒基本是一致的。此时假如我们想把 getValueByKey 方法的缓存有效期单独设置为 600 秒,那我们该如何操作嘞? @Cacheable 注解默认是没有提供有关缓存有效期设置的。想要单独修改 getValueByKey 方法的缓存有效期只能修改全局的缓存有效期。那么有没有别的方法能够为 getValueByKey 方法单独设置缓存有效期嘞?当然是有的,大家请往下看。 自定义 MyRedisCacheManager 缓存 其实我们可以通过自定义 MyRedisCacheManager 类继承 Spring Cache 提供的 RedisCacheManager 类后,重写 createRedisCache(String name, RedisCacheConfiguration cacheConfig) 方法,代码如下, public class MyRedisCacheManager extends RedisCacheManager { public MyRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) { super(cacheWriter, defaultCacheConfiguration); } @Override protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) { String[] array = StringUtils.split(name, "#"); name = array[0]; // 解析 @Cacheable 注解的 value 属性用以单独设置有效期 if (array.length > 1) { long ttl = Long.parseLong(array[1]); cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(ttl)); } return super.createRedisCache(name, cacheConfig); } } MyRedisCacheManager 类逻辑如下, 继承 Spring Cache 提供的 RedisCacheManager 类。 重写 createRedisCache(String name, RedisCacheConfiguration cacheConfig) 方法。 解析 name 参数,根据 # 字符串进行分割,获取缓存 key 名称以及缓存有效期。 接着我们修改下 CacheConfig 类的 cacheManager 方法用以使用 MyRedisCacheManager 类。代码如下, @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { return new MyRedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory), defaultCacheConfig()); } private RedisCacheConfiguration defaultCacheConfig() { return RedisCacheConfiguration.defaultCacheConfig() .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer())) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer())) .computePrefixWith(name -> CACHE_PREFIX + name + ":") .entryTtl(Duration.ofSeconds(600)); } 最后我们修改下 @Cacheable 注解使用方式,在原有 value 属性的 configCache 值后添加 #600,单独标识缓存有效期。代码如下, @Cacheable(value = "configCache#600", key = "#root.methodName + '_' + #root.args[0]") @Override public String getValueByKey(String key) { ... } 看下 getValueByKey 方法生成的 Redis 缓存 key 有效期是多久。如下, OK,看到是 590 秒有效期后,我们就大功告成了,希望本文能对大家有所帮助。 审核编辑:刘清 打开APP阅读更多精彩内容 点击阅读全文 声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉 相关推荐 Cache缓存器Redis L2 Cache配置方案那种更好? 2019-08-05 0 阿里巴巴开源的通用缓存访问框架JetCache介绍 2018-04-24 0 高速缓存(cache)的工作原理是什么?高速缓存可分为哪几类 2021-12-23 0 高速缓存Cache介绍 2023-09-07 0 什么是缓存Cache 2010-01-23 897 什么是Cache 2010-02-22 1016 高速缓存(Cache),高速缓存(Cache)原理是什么? 2010-03-26 6839 Spring应用 1 springXML配置说明 2018-01-13 385 spring配置方式详细介绍 2018-01-28 1426 二级缓存的简单配置教程详解 浅谈二级缓存之功效 2018-08-14 4278 Linux内核Page Cache和Buffer Cache两类缓存的作用及关系如何 2021-07-02 2747 AMD 3D V-cache有望改变缓存设计 2023-02-13 643 使用Spring Cache实现缓存 2023-05-11 779 CPU Cache是如何保证缓存一致性的? 2023-12-04 1472 什么是缓存(Cache)及其作用 2024-12-18 228 全部0条评论 快来发表一下你的评论吧 ! 发送 登录/注册 × 20 完善资料,赚取积分
这里面简单对 RedisCacheConfiguration 缓存配置做一下说明:
serializeKeysWith():设置 Redis 的 key 的序列化规则。
erializeValuesWith():设置 Redis 的 value 的序列化规则。
computePrefixWith():计算 Redis 的 key 前缀。
entryTtl():全局设置 @Cacheable 注解缓存的有效期。
那么使用如上配置生成的 Redis 缓存 key 名称是什么样得嘞?这里用开源项目 crowd-admin 的 ConfigServiceImpl 类下 getValueByKey(String key) 方法举例,
@Cacheable(value = "configCache", key = "#root.methodName + '_' + #root.args[0]") @Override public String getValueByKey(String key) { QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("configKey", key); Config config = getOne(wrapper); if (config == null) { return null; } return config.getConfigValue(); }
执行此方法后,Redis 中缓存 key 名称如下,
crowdgetValueByKey_sys.name
TTL 过期时间是 287,跟我们全局设置的 300 秒基本是一致的。此时假如我们想把 getValueByKey 方法的缓存有效期单独设置为 600 秒,那我们该如何操作嘞?
@Cacheable 注解默认是没有提供有关缓存有效期设置的。想要单独修改 getValueByKey 方法的缓存有效期只能修改全局的缓存有效期。那么有没有别的方法能够为 getValueByKey 方法单独设置缓存有效期嘞?当然是有的,大家请往下看。
自定义 MyRedisCacheManager 缓存
其实我们可以通过自定义 MyRedisCacheManager 类继承 Spring Cache 提供的 RedisCacheManager 类后,重写 createRedisCache(String name, RedisCacheConfiguration cacheConfig) 方法,代码如下,
public class MyRedisCacheManager extends RedisCacheManager { public MyRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) { super(cacheWriter, defaultCacheConfiguration); } @Override protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) { String[] array = StringUtils.split(name, "#"); name = array[0]; // 解析 @Cacheable 注解的 value 属性用以单独设置有效期 if (array.length > 1) { long ttl = Long.parseLong(array[1]); cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(ttl)); } return super.createRedisCache(name, cacheConfig); } }
MyRedisCacheManager 类逻辑如下,
继承 Spring Cache 提供的 RedisCacheManager 类。
重写 createRedisCache(String name, RedisCacheConfiguration cacheConfig) 方法。
解析 name 参数,根据 # 字符串进行分割,获取缓存 key 名称以及缓存有效期。
接着我们修改下 CacheConfig 类的 cacheManager 方法用以使用 MyRedisCacheManager 类。代码如下,
@Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { return new MyRedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory), defaultCacheConfig()); } private RedisCacheConfiguration defaultCacheConfig() { return RedisCacheConfiguration.defaultCacheConfig() .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer())) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer())) .computePrefixWith(name -> CACHE_PREFIX + name + ":") .entryTtl(Duration.ofSeconds(600)); }
最后我们修改下 @Cacheable 注解使用方式,在原有 value 属性的 configCache 值后添加 #600,单独标识缓存有效期。代码如下,
@Cacheable(value = "configCache#600", key = "#root.methodName + '_' + #root.args[0]") @Override public String getValueByKey(String key) { ... }
看下 getValueByKey 方法生成的 Redis 缓存 key 有效期是多久。如下,
OK,看到是 590 秒有效期后,我们就大功告成了,希望本文能对大家有所帮助。
审核编辑:刘清
全部0条评论
快来发表一下你的评论吧 !