springboot3默认的整合下,缓存时间未指定(默认永不失效),且序列化方式为Jdk的Serializable序列化方式,使用起来略有不便。Serializable序列化方式在序列化ID有变化,或者未指定序列化ID时,类的字段一变化,就会报错反序列化失败。
下面是一个可以指定指定缓存时间,指定默认缓存时间,并且使用JSON序列化方式的集成代码。
引入依赖
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
设置默认的RedisTemplate
如果项目中是直接使用RedisTmplate来进行缓存的,需要指定RestTemplate的序列化方式,代码如下:
java
@UtilityClass
public class JacksonJsonSerializerUtil {
public static GenericJackson2JsonRedisSerializer getJackson2JsonRedisSerializer() {
var jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
jackson2JsonRedisSerializer.configure(objectMapper -> {
// add java8 time module
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.activateDefaultTyping(new LaissezFaireSubTypeValidator(),
ObjectMapper.DefaultTyping.EVERYTHING);
JavaTimeModule javaTimeModule = new JavaTimeModule();
objectMapper.registerModule(javaTimeModule);
});
return jackson2JsonRedisSerializer;
}
}
java
@Bean("redisTemplate")
RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory);
var jackson2JsonRedisSerializer = JacksonJsonSerializerUtil.getJackson2JsonRedisSerializer();
// 设置value的序列化规则和key的序列化规则
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
设置@Cacheable的序列化方式
@Cacheable
不使用RedisTemplate,因此上面的定义是无效的,它直接使用CacheManager,因此我们需要自定义。spring提供了自定义的RedisCacheManagerBuilderCustomizer
来支持自定义,我们实现它,并将它注入到spring容器中就可以了。
java
public class MyRedisCacheManagerBuilderSerialCustomizer implements RedisCacheManagerBuilderCustomizer {
@Override
public void customize(RedisCacheManager.RedisCacheManagerBuilder builder) {
RedisSerializer<String> stringRedisSerializer = new StringRedisSerializer();
var jackson2JsonRedisSerializer = getJackson2JsonRedisSerializer();
var configuration = builder.cacheDefaults()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringRedisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer));
builder.cacheDefaults(configuration);
var configuredCaches = builder.getConfiguredCaches();
// 针对有的缓存存在自定义配置的情况,读取所有缓存的配置,设置序列化方法
for (String configuredCache : configuredCaches) {
var cacheConfig = builder.getCacheConfigurationFor(configuredCache);
cacheConfig.ifPresent(config -> {
var newConfig = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringRedisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer));
builder.withCacheConfiguration(configuredCache, newConfig);
});
}
}
}
java
// 注入到spring容器中
@Bean
MyRedisCacheManagerBuilderSerialCustomizer myRedisCacheManagerBuilderSerialCustomizer() {
return new MyRedisCacheManagerBuilderSerialCustomizer();
}
自定义缓存的过期时间,以及默认过期时间
我们自定义一个配置来支持设置过期时间,配置如下:
yaml
myservice:
redis:
# 采用ISO-8601时间格式。格式为:PnDTnHnMnS (n为个数)
#例如:P1Y2M3DT4H5M6.7S = 1年2个月3天4小时5分钟6.7秒
default-expire-time: PT30M
cache-and-expires:
- cache-name: test
expire-time: PT10M
java
@Data
public class CacheAndExpire {
private String cacheName;
private Duration expireTime;
}
java
@Slf4j
public class MyRedisCacheManagerBuilderCustomizer implements RedisCacheManagerBuilderCustomizer {
private final MyRedisConfig myRedisConfig;
public MyRedisCacheManagerBuilderCustomizer(MyRedisConfig myRedisConfig) {
this.myRedisConfig = myRedisConfig;
}
@Override
public void customize(RedisCacheManager.RedisCacheManagerBuilder builder) {
log.info("my redis expire-time config!");
var configuration = builder.cacheDefaults()
.entryTtl(myRedisConfig.getDefaultExpireTime());
builder.cacheDefaults(configuration);
log.info("my redis expire-time cacheAndExpire has {} configs!", myRedisConfig.getCacheAndExpires().size());
for (CacheAndExpire cacheAndExpire : myRedisConfig.getCacheAndExpires()) {
var cacheConfig = builder.getCacheConfigurationFor(cacheAndExpire.getCacheName()).orElse(configuration);
builder.withCacheConfiguration(cacheAndExpire.getCacheName(), cacheConfig.entryTtl(cacheAndExpire.getExpireTime()));
}
}
}
将bean注入到Spring容器中
java
@EnableConfigurationProperties({MyRedisConfig.class})
public class RedisConfig {
@Bean
MyRedisCacheManagerBuilderCustomizer myRedisCacheManagerBuilderCustomizer(MyRedisConfig myRedisConfig) {
return new MyRedisCacheManagerBuilderCustomizer(myRedisConfig);
}
}