作者最近在开发公司项目时使用到 Redis 缓存,并在翻看前人代码时,看到了一种关于
@Cacheable
注解的自定义缓存有效期的解决方案,感觉比较实用,因此作者自己拓展完善了一番后分享给各位。
Spring 缓存常规配置
Spring Cache
框架给我们提供了 @Cacheable
注解用于缓存方法返回内容。但是 @Cacheable
注解不能定义缓存有效期。这样的话在一些需要自定义缓存有效期的场景就不太实用。
按照 Spring Cache
框架给我们提供的 RedisCacheManager
实现,只能在全局设置缓存有效期。这里给大家看一个常规的 CacheConfig
缓存配置类,代码如下:
@EnableCaching
@Configuration
public class CacheConfig extends CachingConfigurerSupport {...private RedisSerializer<String> keySerializer() {return new StringRedisSerializer();}private RedisSerializer<Object> valueSerializer() {return new GenericFastJsonRedisSerializer();}public static final String CACHE_PREFIX = "crowd:";@Beanpublic 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 的序列化规则。 -
serializeValuesWith()
:设置 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<Config> 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 秒,那我们该如何操作嘞?
@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);}@Overrideprotected 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 秒有效期后,我们就大功告成了,希望本文能对大家有所帮助。