You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring-data-redis @Cacheable出现LinkedHashMap转MyObject类型转换异常

嘿,这个问题太常见了!我之前在做Spring Boot缓存的时候也踩过这个坑,本质就是Redis反序列化时丢失了对象的类型信息导致的。

咱们先理清楚为什么第一次调用没问题,第二次就炸了:

  • 第一次调用API时,直接从Mongo获取MyObject实例,返回给客户端的过程中,对象的类型是明确的,所以一切正常;
  • 第二次调用时,Redis返回的是序列化后的JSON字符串,但默认的序列化器(比如Jackson2JsonRedisSerializer)在序列化时没有把MyObject的全类名存进去,反序列化的时候只能把JSON转成通用的LinkedHashMap,这时候你强转成MyObject当然会抛出ClassCastException。

解决方案1:使用带类型信息的序列化器

最直接的办法是用GenericJackson2JsonRedisSerializer代替默认的序列化器,它会在序列化后的JSON中自动加入@class字段,记录对象的全类名,反序列化时就能精准识别类型了。

你可以通过配置RedisTemplate和CacheManager来实现:

@Configuration
public class RedisCacheConfig {

    // 配置RedisTemplate
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        // 初始化GenericJackson2JsonRedisSerializer,自带类型信息存储
        GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer();

        // 设置value和hashValue的序列化器
        redisTemplate.setValueSerializer(jsonSerializer);
        redisTemplate.setHashValueSerializer(jsonSerializer);

        // key用String序列化器就行
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());

        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    // 如果用@Cacheable这类Spring Cache注解,必须配置CacheManager
    @Bean
    public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
        RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig()
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));

        return RedisCacheManager.builder(redisConnectionFactory)
                .cacheDefaults(cacheConfig)
                .build();
    }
}

解决方案2:自定义ObjectMapper并开启类型映射

如果你需要更精细地控制Jackson的序列化行为,可以手动配置ObjectMapper,开启默认类型映射,然后传给GenericJackson2JsonRedisSerializer:

@Bean
public GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer() {
    ObjectMapper objectMapper = new ObjectMapper();
    // 开启类型信息,NON_FINAL表示除了final类都记录类型
    objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
    return new GenericJackson2JsonRedisSerializer(objectMapper);
}

重要提醒!

配置完新的序列化器后,一定要清空Redis中已有的缓存数据!因为之前缓存的JSON是没有类型信息的,即使换了序列化器,读取旧数据还是会报错。

这样调整之后,第二次从Redis读取时,就能正确把JSON反序列化为MyObject实例,不会再出现ClassCastException了。

内容的提问来源于stack exchange,提问作者hardik.desai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:28:21