You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Spring Data Cache集成Redis:如何避免在序列化JSON中存储占用大量空间的类名?

解决Spring Data Cache + Redis中JSON序列化的@class字段冗余问题

好问题!默认情况下,GenericJackson2JsonRedisSerializer(也就是RedisSerializer.json())会自动添加@class字段来存储类型信息,方便反序列化时识别对象类型。但正如你所说,当我们在@Cacheable方法中明确知道返回类型时,这个字段完全是多余的,还会浪费Redis的内存空间。下面提供几个可行的解决方案:

方案1:针对特定POJO使用Jackson2JsonRedisSerializer

如果你的缓存方法只返回特定的POJO类型(比如示例中的MyPOJO),可以直接使用Jackson2JsonRedisSerializer并指定具体类型,而不是泛型的GenericJackson2JsonRedisSerializer。这样序列化器会明确知道要处理的类型,无需额外存储@class字段。

修改你的缓存配置代码如下:

// 创建针对MyPOJO的专属序列化器
RedisSerializer<MyPOJO> myPOJOValueSerializer = new Jackson2JsonRedisSerializer<>(MyPOJO.class);

return RedisCacheManager.builder(redisConnectionFactory)
    .cacheDefaults(
        RedisCacheConfiguration.defaultCacheConfig()
            .serializeKeysWith(SerializationPair.fromSerializer(RedisSerializer.string()))
            .serializeValuesWith(SerializationPair.fromSerializer(myPOJOValueSerializer))
    )
    .build();

这样序列化后的JSON就会是干净的{"hello":"world"},不再包含@class字段,反序列化时也能直接正确转换为MyPOJO类型。

方案2:全局关闭GenericJackson2JsonRedisSerializer的类型信息

如果你的项目中有多个不同的POJO需要缓存,且所有@Cacheable方法的返回类型都是明确的,可以自定义GenericJackson2JsonRedisSerializer的ObjectMapper,完全关闭类型信息的自动添加。

示例代码:

// 初始化GenericJackson2JsonRedisSerializer
GenericJackson2JsonRedisSerializer customJsonSerializer = new GenericJackson2JsonRedisSerializer();
ObjectMapper objectMapper = customJsonSerializer.getObjectMapper();

// 关闭默认的类型信息自动添加
objectMapper.activateDefaultTyping(
    objectMapper.getPolymorphicTypeValidator(),
    ObjectMapper.DefaultTyping.NONE // 完全禁用类型信息
);

// 配置缓存管理器
return RedisCacheManager.builder(redisConnectionFactory)
    .cacheDefaults(
        RedisCacheConfiguration.defaultCacheConfig()
            .serializeKeysWith(SerializationPair.fromSerializer(RedisSerializer.string()))
            .serializeValuesWith(SerializationPair.fromSerializer(customJsonSerializer))
    )
    .build();

⚠️ 注意:使用这个方案时,必须确保所有缓存的对象在反序列化时的目标类型和序列化时的类型完全一致,否则会抛出ClassCastException

方案3:为不同缓存空间配置差异化序列化规则

如果你的项目中既有明确类型的缓存,又有需要保留类型信息的泛型缓存,可以针对不同的缓存名称(即@Cacheable中的value属性)配置不同的序列化规则。

示例代码:

return RedisCacheManager.builder(redisConnectionFactory)
    // 为myPOJOCache缓存空间使用专属序列化器
    .withCacheConfiguration("myPOJOCache",
        RedisCacheConfiguration.defaultCacheConfig()
            .serializeValuesWith(SerializationPair.fromSerializer(new Jackson2JsonRedisSerializer<>(MyPOJO.class)))
    )
    // 为其他缓存空间保留默认的泛型序列化(带@class字段)
    .withCacheConfiguration("genericCache",
        RedisCacheConfiguration.defaultCacheConfig()
            .serializeValuesWith(SerializationPair.fromSerializer(RedisSerializer.json()))
    )
    .build();

这样可以灵活应对不同场景的缓存需求,平衡内存占用和类型安全性。

额外优化建议

除了去掉@class字段,你还可以通过以下方式进一步减少Redis中的JSON体积:

  • 配置ObjectMapper忽略空值字段:objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL)
  • 启用JSON压缩:在RedisCacheConfiguration中添加.computePrefixWith(cacheName -> "compressed:" + cacheName),配合Redis的压缩存储(需要Redis支持)

内容的提问来源于stack exchange,提问作者ch271828n

火山引擎 最新活动