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<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}
@Bean
public CustomizerRedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {
CustomizerRedisCacheManager redisCacheManager = new CustomizerRedisCacheManager(redisTemplate);
redisCacheManager.setUsePrefix(true); // 寫入redis中保留cacheName前綴
return redisCacheManager;
}
}
使用@Cacheable驗證緩存失效時間:
@Cacheable(value = "ota.vehicle.series#20", key = "#k + '_' + 123")
public String testExpire(String k) {
return "test expire";
}
緩存20秒后過期,效果如下:
20秒后過期,key被刪除
這里需要注意一點:因為cacheName帶上了#20,這樣寫到redis中也會帶上這個前綴,所以需要去掉這個前綴,上面CustomizerRedisCacheManager 類中cacheName = cacheName.substring(0, expireIndex);
就是將此部分截斷再寫入。
轉自:https://blog.csdn.net/huangdi1309/article/details/103784115?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control