Spring Session集成Redis遇NotSerializableException问题求助
这个问题我之前帮同事排查过,本质是你的HttpSession里不小心存入了被Spring CGLIB代理的Bean实例,而这个代理类org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor并没有实现Serializable接口,所以Redis序列化Session的时候就抛出了异常。
下面是具体的解决步骤,按优先级从高到低推荐:
1. 排查并修正Session存储的对象(最推荐)
首先检查你代码里所有调用session.setAttribute()的地方,看看是不是把Spring管理的Bean(比如标注了@Service、@Component、@Configuration的类实例)直接存入了Session。这些Bean默认是被CGLIB动态代理的,代理类本身不支持序列化。
解决思路是:不要直接存Bean实例,而是提取需要的业务数据,放到一个**实现了Serializable接口的普通POJO(DTO)**里再存入Session。
举个例子:
错误写法:
@Autowired private UserService userService; // 错误:直接存入Spring代理的Bean session.setAttribute("userService", userService);
正确写法:
// 先定义一个可序列化的DTO类 public class UserSessionDTO implements Serializable { private Long userId; private String username; // 无参构造、getter/setter } // 提取业务数据存入DTO UserSessionDTO userSessionInfo = new UserSessionDTO(); userSessionInfo.setUserId(userService.getCurrentUserId()); userSessionInfo.setUsername(userService.getCurrentUsername()); // 存入Session session.setAttribute("userSessionInfo", userSessionInfo);
2. 若必须存Bean,调整Spring代理方式(不推荐)
如果确实有需求要把Bean存入Session,需要做两个调整:
- 让你的Bean类实现
Serializable接口; - 将Spring的代理方式从CGLIB改为JDK动态代理(JDK代理生成的类默认支持序列化,但要求Bean必须实现至少一个接口)。
配置方式:
在你的@Configuration类上添加注解:
@EnableAspectJAutoProxy(proxyTargetClass = false)
或者XML配置:
<aop:aspectj-autoproxy proxy-target-class="false"/>
3. 替换Redis序列化器(备选方案)
如果不想修改Session存储的内容,可以替换Spring Session使用的Redis序列化器,用JSON序列化代替默认的JDK序列化,这样不需要对象实现Serializable接口。
配置示例:
@Configuration public class RedisSessionConfig { @Bean public RedisSerializer<Object> springSessionDefaultRedisSerializer() { // 使用Jackson JSON序列化器 Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class); ObjectMapper objectMapper = new ObjectMapper(); // 配置Jackson支持序列化所有类型,包括私有字段等 objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); serializer.setObjectMapper(objectMapper); return serializer; } }
注意:使用JSON序列化时,要确保Session中的对象能被Jackson正确处理(比如有无参构造函数、字段可访问等)。
内容的提问来源于stack exchange,提问作者Diogo

