Spring Boot读取Redis缓存报错SerializationException无法反序列化
问题根因
报错是三个原因共同导致的:
- 你配置的RedisTemplate只设置了HashValue的序列化规则,默认的Value序列化用的是JDK原生序列化,会把Java类全限定名等信息写入缓存,反序列化时对类加载环境要求极高
- JPA的
getById方法默认是懒加载,返回的是UserEntity的动态代理对象,JDK序列化时会把代理类的信息写入缓存,反序列化时找不到对应代理类就会抛类不存在异常 - Spring Boot Devtools的
RestartClassLoader和默认应用类加载器是隔离的,序列化时用的类加载器和反序列化时不一致,也会触发类找不到的错误
解决步骤
1. 调整Redis序列化配置
把RedisTemplate的序列化规则改成Jackson JSON序列化,规避JDK序列化的类加载依赖问题,调整后的配置如下:
@Configuration @EnableCaching public class RedisCacheConfiguration { @Bean JedisConnectionFactory jedisConnectionFactory() { JedisConnectionFactory jedisConFactory = new JedisConnectionFactory(); jedisConFactory.setHostName("localhost"); jedisConFactory.setPort(6379); return jedisConFactory; } @Bean public RedisTemplate<String, Object> redisTemplate() { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(jedisConnectionFactory()); // 配置Jackson序列化器 Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); // 统一所有类型的序列化规则 template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(jackson2JsonRedisSerializer); template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } }
Spring Boot默认的web启动器已经包含Jackson相关依赖,无需额外引入。
2. 处理Devtools类加载器冲突
如果不需要热重启功能,直接删除pom.xml或gradle构建文件中的spring-boot-devtools依赖即可彻底解决类加载器隔离问题。
如果需要保留Devtools,在项目的src/main/resources目录下新建META-INF/spring-devtools.properties文件,加入以下配置:
restart.include.redis=/spring-data-redis-.*.jar
该配置会让Spring Data Redis的相关类和你的业务类使用同一个类加载器加载,避免加载冲突。
3. 清理Redis旧缓存
之前用JDK序列化写入的缓存已经包含旧的类信息,需要删除Redis中所有前缀为user的缓存key,避免反序列化旧数据继续报错。
可选优化
把userRepository.getById换成userRepository.findById,避免懒加载返回代理对象的问题,进一步降低序列化异常的概率。
内容的提问来源于stack exchange,提问作者Umut
相关产品推荐
相关产品推荐

