启动类开启注解
@EnableCaching
自定义RedisCacheManager,使其能在注解上配置过期时间
import cn.hutool.core.util.StrUtil;
import org.springframework.data.redis.cache.*;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import java.time.Duration;
/**
* @author jiangli
* @since 2021/1/12 15:07
* 通过cacheName自定义过期时间的RedisCacheManager
* 支持直接使用cacheName来定义过期时间
* cacheName:name#time time为过期时间,单位秒,0为不过期
* 例如:test#100 意思是定义一个名为test#100的缓存,且过期时间为100秒
*/
public class CustomTtlRedisCacheManager extends RedisCacheManager {
public CustomTtlRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
super(cacheWriter, defaultCacheConfiguration);
}
@Override
protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
Duration ttl = getTtlByName(name);
if (ttl != null) {
//证明在cacheName上使用了过期时间,需要修改配置中的ttl
cacheConfig = cacheConfig.entryTtl(ttl);
}
//修改缓存key和value值的序列化方式
cacheConfig = cacheConfig.computePrefixWith(DEFAULT_CACHE_KEY_PREFIX)
.serializeValuesWith(DEFAULT_PAIR);
return super.createRedisCache(name, cacheConfig);
}
/**
* 缓存参数的分隔符
* 数组元素0=缓存的名称
* 数组元素1=缓存过期时间TTL
*/
private static final String DEFAULT_SEPARATOR = "#";
/**
* 通过name获取过期时间
*
* @param name
* @return
*/
private Duration getTtlByName(String name) {
if (name == null) {
return null;
}
//根据分隔符拆分字符串,并进行过期时间ttl的解析
String[] cacheParams = name.split(DEFAULT_SEPARATOR);
if (cacheParams.length > 1) {
String ttl = cacheParams[1];
if (!StrUtil.isEmpty(ttl)) {
try {
return Duration.ofSeconds(Long.parseLong(ttl));
} catch (Exception e) {
}
}
}
return null;
}
/**
* 默认的key前缀
*/
private static final CacheKeyPrefix DEFAULT_CACHE_KEY_PREFIX = cacheName -> cacheName + ":";
/**
* 默认序列化方式为json
*/
private static final RedisSerializationContext.SerializationPair<Object> DEFAULT_PAIR = RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer());
}
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
/**
* @author jiangli
* @since 2021/1/12 15:07
*/
@Configuration
public class RedisConfig {
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
//初始化一个RedisCacheWriter
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
//初始化一个RedisCacheConfiguration
RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig();
//返回一个自定义的CacheManager
return new CustomTtlRedisCacheManager(redisCacheWriter, defaultCacheConfig);
}
}
使用
// 将正确的结果缓存到redis unless如果不
@GetMapping("/list")
@Cacheable(cacheNames = "product#7200", key = "#root.methodName", unless = "#result.get('success')==false")
public R list() {
// 查询所有上架的商品
// ProductVOS productVOS = ......
return R.ok(productVOS);
}
/**
* 商品新增/修改
* 清除缓存
*/
@PostMapping("/save")
@CacheEvict(cacheNames = "product#7200",allEntries=true)
public ModelAndView save(@Validated ProductForm form, BindingResult bindingResult, Map<String, Object> map) {
// 业务逻辑 ......
map.put("url", "/sell/seller/product/list");
return new ModelAndView("common/success", map);
}
redis中的缓存已经设置了过期时间
补充@Cacheable key的使用
自定义策略是指我们可以通过Spring的EL表达式来指定我们的key。这里的EL表达式可以使用方法参数及它们对应的属性。使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”。下面是几个使用参数作为key的示例。
@Cacheable(value="users", key="#id")
public User find(Integer id) {
returnnull;
}
@Cacheable(value="users", key="#p0")
public User find(Integer id) {
returnnull;
}
@Cacheable(value="users", key="#user.id")
public User find(User user) {
returnnull;
}
@Cacheable(value="users", key="#p0.id")
public User find(User user) {
returnnull;
}
除了上述使用方法参数作为key之外,Spring还为我们提供了一个root对象可以用来生成key。通过该root对象我们可以获取到以下信息。