Spring 缓存注解这样用,太香了!
作者最近在开发公司项目时使用到 Redis 缓存,并在翻看前人代码时,看到了一种关于 @Cacheable
注解的自定义缓存有效期的解决方案,感觉比较实用,因此作者自己拓展完善了一番后分享给各位。
Spring 缓存常规配置
Spring Cache
框架给我们提供了 @Cacheable
注解用于缓存方法返回内容。但是 @Cacheable
注解不能定义缓存有效期。这样的话在一些需要自定义缓存有效期的场景就不太实用。
按照 Spring Cache
框架给我们提供的 RedisCacheManager
实现,只能在全局设置缓存有效期。这里给大家看一个常规的 CacheConfig
缓存配置类,代码如下,
@EnableCaching
@Configuration
public class CacheConfig extends CachingConfigurerSupport {
...
private RedisSerializerkeySerializer() {
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()
:全局设置
注解缓存的有效期。
那么使用如上配置生成的 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 名称如下,
crowd:configCache:getValueByKey_sys.name
ttl 过期时间是 287,跟我们全局设置的 300 秒基本是一致的。此时假如我们想把
getValueByKey
方法的缓存有效期单独设置为 600 秒,那我们该如何操作嘞?
注解默认是没有提供有关缓存有效期设置的。想要单独修改
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 名称以及缓存有效期。
重新设置缓存 key 名称以及缓存有效期。
调用父类的 createRedisCache(name, cacheConfig)
方法来完成缓存写入。
接着我们修改下
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));
}
最后在使用
注解时,在原有
value
属性的 configCache
值后添加 #600
,单独标识缓存有效期。代码如下,
@Cacheable(value = "configCache#600", key = "#root.methodName + '_' + #root.args[0]")
@Override
public String getValueByKey(String key) {
...
}
看下
getValueByKey
方法生成的 Redis 缓存 key 有效期是多久。如下,
OK,看到是 590 秒有效期后,我们就大功告成了。到这里我们就完成了对
注解的自定义缓存有效期功能开发。
作者:waynaqua
来源:juejin.cn/post/7299353390764179506