我们都知道springCache定义了缓存规范,其中redis的解决方案并不支持每个缓存key独自设置过期时间,本方案通过定义cacheName为特定格式,从而设置缓存过期时间。支持设置过期时间单位(默认秒)
1、重写RedisCacheManager的createRedisCache方法。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import java.time.Duration;
import java.util.Map;
/**
* @author Tzx
* @date 2022/12/13 19:33
*/
public class TaRedisCacheManager extends RedisCacheManager {
private static final Logger LOGGER = LoggerFactory.getLogger(TaRedisCacheManager.class);
public TaRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
super(cacheWriter, defaultCacheConfiguration);
}
public TaRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration, String... initialCacheNames) {
super(cacheWriter, defaultCacheConfiguration, initialCacheNames);
}
public TaRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration, boolean allowInFlightCacheCreation, String... initialCacheNames) {
super(cacheWriter, defaultCacheConfiguration, allowInFlightCacheCreation, initialCacheNames);
}
public TaRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration, Map<String, RedisCacheConfiguration> initialCacheConfigurations) {
super(cacheWriter, defaultCacheConfiguration, initialCacheConfigurations);
}
public TaRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration, Map<String, RedisCacheConfiguration> initialCacheConfigurations, boolean allowInFlightCacheCreation) {
super(cacheWriter, defaultCacheConfiguration, initialCacheConfigurations, allowInFlightCacheCreation);
}
@Override
protected RedisCache createRedisCache(String name, @Nullable RedisCacheConfiguration cacheConfig) {
String[] params = name.split("#");
String cacheName = params[0];
if (params.length > 1) {
cacheConfig = this.entryTtl(cacheName, params[1], cacheConfig);
}
return super.createRedisCache(cacheName, cacheConfig);
}
private RedisCacheConfiguration entryTtl(String cacheName, String ttlStr, @Nullable RedisCacheConfiguration cacheConfig) {
Assert.notNull(cacheConfig, "RedisCacheConfiguration is required; it must not be null");
// 根据传参设置缓存失效时间
Duration duration = parseDuration(ttlStr);
cacheConfig = cacheConfig.entryTtl(duration);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("redisCache {} 过期时间为{}秒", cacheName, duration.getSeconds());
}
return cacheConfig;
}
private Duration parseDuration(String ttlStr) {
String timeUnit = ttlStr.substring(ttlStr.length() - 1);
switch (timeUnit) {
case "d":
return Duration.ofDays(parseLong(ttlStr));
case "h":
return Duration.ofHours(parseLong(ttlStr));
case "m":
return Duration.ofMinutes(parseLong(ttlStr));
case "s":
return Duration.ofSeconds(parseLong(ttlStr));
default:
return Duration.ofSeconds(Long.parseLong(ttlStr));
}
}
private long parseLong(String ttlStr) {
return Long.parseLong(ttlStr.substring(0, ttlStr.length() - 1));
}
}
2、把TaRedisCacheManager交给spring管理
/**
* 自定义RedisCacheManager,用于在使用@Cacheable时设置ttl
*/
@Bean({"redisCacheManager"})
public RedisCacheManager redisCacheManager(RedisTemplate<?, ?> redisTemplate) {
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(Objects.requireNonNull(redisTemplate.getConnectionFactory()));
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer()));
return new TaRedisCacheManager(redisCacheWriter, redisCacheConfiguration);
}
3、使用,为testCache设置过期时间为10小时
@Cacheable(value = "testCache#10h", key = "#userId", condition = "#userId != null && #userName == null ")
public String testCache(String userId, String userName) {
System.out.println("=====================>");
ThreadUtil.sleep(1000);
return "success";
}
注:该方案还是修改了原springCache的设计,而且不支持过期自动刷新,所以改造了一下,注解式[SpirngCache、Redis指定过期时间、到期自动刷新_csdn_Ty的博客-CSDN博客]