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);
    }
}
相关推荐
登云时刻2 小时前
Kubernetes集群外连接redis集群和使用redis-shake工具迁移数据(一)
redis·kubernetes·bootstrap
一条晒干的咸魚4 小时前
【Web前端】创建我的第一个 Web 表单
服务器·前端·javascript·json·对象·表单
煎饼小狗7 小时前
Redis五大基本类型——Zset有序集合命令详解(命令用法详解+思维导图详解)
数据库·redis·缓存
秋意钟9 小时前
缓存雪崩、缓存穿透【Redis】
redis
简 洁 冬冬9 小时前
046 购物车
redis·购物车
雯0609~10 小时前
网页F12:缓存的使用(设值、取值、删除)
前端·缓存
soulteary10 小时前
突破内存限制:Mac Mini M2 服务器化实践指南
运维·服务器·redis·macos·arm·pika
wkj00111 小时前
php操作redis
开发语言·redis·php
菠萝咕噜肉i12 小时前
超详细:Redis分布式锁
数据库·redis·分布式·缓存·分布式锁
登云时刻13 小时前
Kubernetes集群外连接redis集群和使用redis-shake工具迁移数据(二)
redis·容器·kubernetes