springboot3 + redis 缓存整合 支持@Cacheable 设置Json序列化,并支持按缓存设置缓存时间

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);
    }
}
相关推荐
奋斗的老史1 小时前
Spring Retry + Redis Watch实现高并发乐观锁
java·redis·spring
loop lee2 小时前
Redis - Token & JWT 概念解析及双token实现分布式session存储实战
java·redis
李匠20243 小时前
大数据学习之Redis 缓存数据库二,Scala分布式语言一
大数据·数据库·缓存
_oP_i3 小时前
.NET Core工程中appsettings.json的HTTP和HTTPS端口是否能一样?
http·json·.netcore
一只搬砖的猹3 小时前
cJson系列——常用cJson库函数
linux·前端·javascript·python·物联网·mysql·json
怒码ing4 小时前
Java包装类型的缓存
java·开发语言·缓存
凡人的AI工具箱4 小时前
每天40分玩转Django:Django缓存
数据库·人工智能·后端·python·缓存·django
安然望川海4 小时前
springboot 使用注解设置缓存时效
spring boot·后端·缓存
大G哥4 小时前
k8s创建单例redis设置密码
数据库·redis·云原生·容器·kubernetes
A22745 小时前
Redis——双写一致性
java·redis·缓存