今天是2019年最后一天,回想年初立下的小目标,貌似都完成的不理想-_- 还得继续努力啊!!!生活还在继续,加油。
最近刚好在使用spring cache做缓存的时候,有需要针对不同的key设置过期时间的场景,找了下资料,实现这个功能,做个总结。
spring cache 集成redis是基于spring-data-redis组件开发的一直通过注解就能轻松实现redis缓存操作的框架。
但原生的spring cache不支持缓存过期,默认都是没有过期时间的,以下实现自定义缓存过期时间。
spring-data-redis版本是1.8.11,所以需要使用此版本或者兼容此版本的其他版本。
先看spring的RedisCacheManager类代码:
protected RedisCache createCache(String cacheName) {
long expiration = computeExpiration(cacheName);
return new RedisCache(cacheName, (usePrefix ? cachePrefix.prefix(cacheName) : null), redisOperations, expiration,
cacheNullValues);
}
protected long computeExpiration(String name) {
Long expiration = null;
if (expires != null) {
expiration = expires.get(name);
}
return (expiration != null ? expiration.longValue() : defaultExpiration);
}
其中expiration变量其实就是过期时间(单位是秒),如果我们不做任何事情,那么expiration 就是defaultExpiration,这个值是0,也就是永不过期。所以我们可以从这个入手,自定义一个RedisCacheManager,覆盖createCache方法。
自定义类:CustomizerRedisCacheManager
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.cache.Cache;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.util.CollectionUtils;
import java.util.*;
/**
* @Description RedisCacheManager
* @Author huangd
* @Date 2019-12-31 16:09
**/
@Slf4j
public class CustomizerRedisCacheManager extends RedisCacheManager {
private static final char SEPARATOR = '#'; // 过期时间分隔符,可以用其他符号
public CustomizerRedisCacheManager(RedisOperations redisOperations) {
super(redisOperations);
}
@Override
protected RedisCache createCache(String cacheName) {
long defaultExpiration = computeExpiration(cacheName);
int expireIndex = cacheName.indexOf(SEPARATOR);
if (expireIndex > 0) {
defaultExpiration = getExpirationTime(cacheName, expireIndex, defaultExpiration);
cacheName = cacheName.substring(0, expireIndex);
}
return new RedisCache(cacheName, (isUsePrefix() ? getCachePrefix().prefix(cacheName) : null),
getRedisOperations(), defaultExpiration);
}
/**
* 缓存时间
* @param name cacheName cache#3600
* @param expireIndex
* @param defaultExpiration 默认过期时间
* @return
*/
protected long getExpirationTime(String name, int expireIndex, long defaultExpiration) {
String expirationAsString = name.substring(expireIndex + 1);
try {
Long expiration = NumberUtils.toLong(expirationAsString, defaultExpiration);
return expiration.longValue();
} catch (Exception e) {
log.error("获取指定cacheName:{},缓存失效时间异常:{}", name, e.getMessage());
}
return defaultExpiration;
}
}
设置redis的key序列化
@Configuration
public class CustomCachingConfigurerSupport extends CachingConfigurerSupport {
@Bean
public RedisTemplate
使用@Cacheable验证缓存失效时间:
@Cacheable(value = "ota.vehicle.series#20", key = "#k + '_' + 123")
public String testExpire(String k) {
return "test expire";
}
这里需要注意一点:因为cacheName带上了#20,这样写到redis中也会带上这个前缀,所以需要去掉这个前缀,上面CustomizerRedisCacheManager 类中cacheName = cacheName.substring(0, expireIndex);
就是将此部分截断再写入。