Spring Session存Redis时重定向发Flash对象遇类型转换异常
问题描述
在登录校验场景中,添加spring-session-data-redis依赖实现会话持久化与多设备踢除功能后,使用redirectAttributes.addFlashAttribute传递校验失败消息时抛出ClassCastException,异常栈核心信息如下:
Caused by: java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class org.springframework.web.servlet.FlashMap (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; org.springframework.web.servlet.FlashMap is in unnamed module of loader 'app') at org.springframework.web.servlet.support.AbstractFlashMapManager.getExpiredFlashMaps(AbstractFlashMapManager.java:130) ~[spring-webmvc-6.2.1.jar:6.2.1] at org.springframework.web.servlet.support.AbstractFlashMapManager.retrieveAndUpdate(AbstractFlashMapManager.java:99) ~[spring-webmvc-6.2.1.jar:6.2.1] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-6.2.1.jar:6.2.1] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) ~[spring-webmvc-6.2.1.jar:6.2.1] ... 42 common frames omitted
注释掉addFlashAttribute相关代码后,重定向流程正常但无法展示提示消息,现需明确该异常的根本原因。
核心配置与代码
pom.xml关键依赖
<?xml version="1.0" encoding="UTF-8"?> <project ...> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.4.1</version> <relativePath/> </parent> ... <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> <version>3.4.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>3.4.1</version> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-core</artifactId> <version>3.4.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>3.4.1</version> </dependency> <!-- 新增的Redis会话持久化依赖 --> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> <version>3.4.1</version> </dependency> </dependencies> ... </project>
LoginController核心逻辑
@Controller public class LoginController { @GetMapping("login") public String getLogin() { return "login"; } @PostMapping("login") public RedirectView postLogin(@Valid @ModelAttribute LoginRequest loginRequest, HttpServletRequest request, RedirectAttributes redirectAttributes) { String alertMessage = null; String username = loginRequest.getUsername(); User user = userService.selectByUsernameAndPassword(username, loginRequest.getPassword()); if (Objects.isNull(user)) { alertMessage = "Invalid username/password."; } else if (user.getEnableFlag() != EnableToggle.ENABLE) { alertMessage = "User account is disabled."; } if (StringUtils.isBlank(alertMessage)) { HttpSession currentSession = request.getSession(); // 多设备会话踢除标记 currentSession.setAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username); return new RedirectView("/", true); } else { redirectAttributes.addFlashAttribute("username", username); redirectAttributes.addFlashAttribute("alert", alertMessage); return new RedirectView("/login", true); } } }
异常原因分析
该ClassCastException的根源是Spring Session使用Redis存储会话时,默认序列化机制无法正确还原FlashMap类型,具体逻辑链如下:
- 调用
redirectAttributes.addFlashAttribute时,Spring Web会将闪存数据封装为FlashMap对象,并存入当前HttpSession。 - 添加
spring-session-data-redis后,会话数据被持久化到Redis,默认使用的序列化器(如JdkSerializationRedisSerializer或未开启类型信息的GenericJackson2JsonRedisSerializer)会将FlashMap序列化为通用的LinkedHashMap结构,丢失了原始类型信息。 - 重定向后的请求尝试从Redis中读取并反序列化闪存数据时,得到的是
LinkedHashMap实例,但AbstractFlashMapManager期望的是FlashMap类型,因此抛出类型转换异常。
本质上,Spring Web的FlashMap并非为分布式会话场景设计,默认序列化机制无法处理其类型识别需求,导致反序列化失败。
内容的提问来源于stack exchange,提问作者Gideon
相关产品推荐
相关产品推荐

