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 小时前
Java 连接 Redis 的驱动(Jedis、Lettuce、Redisson、Spring Data Redis)分类及对比
java·redis·spring
松韬2 小时前
Spring + Redisson:从 0 到 1 搭建高可用分布式缓存系统
java·redis·分布式·spring·缓存
天上掉下来个程小白3 小时前
Redis-14.在Java中操作Redis-Spring Data Redis使用方式-操作列表类型的数据
java·redis·spring·springboot·苍穹外卖
·云扬·3 小时前
深度剖析 MySQL 与 Redis 缓存一致性:理论、方案与实战
redis·mysql·缓存
努力搬砖的咸鱼3 小时前
Qt中的数据解析--XML与JSON处理全攻略
xml·开发语言·qt·json
汤姆大聪明4 小时前
Redisson 操作 Redis Stream 消息队列详解及实战案例
redis·spring·缓存·maven
敲上瘾6 小时前
高并发内存池(二):Central Cache的实现
linux·服务器·c++·缓存·哈希算法
csjane107918 小时前
Redis原理:rename命令
java·redis
Feng.Lee18 小时前
聊一聊缓存如何进行测试
功能测试·测试工具·缓存
小吴先生66620 小时前
Groovy 规则执行器,加载到缓存
java·开发语言·缓存·groovy