作者最近在開發公司專案時使用到 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:";
@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<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);
}
@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));
}
最後在使用 @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 秒有效期後,我們就大功告成了。到這裡我們就完成了對 @Cacheable
註解的自定義快取有效期功能開發。
關注公眾號【waynblog】每週分享技術乾貨、開源專案、實戰經驗、國外優質文章翻譯等,您的關注將是我的更新動力!