@SessionAttributes在多Servlet上下文连续GET请求中失效问题排查
你的问题核心在于跨DispatcherServlet(不同Servlet上下文)时,@SessionAttributes的工作机制与Session共享的限制,具体拆解如下:
1. @SessionAttributes的绑定范围
Spring MVC的@SessionAttributes注解是与当前控制器所属的DispatcherServlet实例绑定的。每个DispatcherServlet(对应你的book-servlet.xml和report-servlet.xml)拥有独立的WebApplicationContext,并负责管理自己管辖范围内的控制器的Session属性。
当BookController处理请求时,book-servlet的DispatcherServlet会识别到@SessionAttributes("login"),在请求结束后自动将ModelMap中名为login的属性存入当前HttpSession——这一步能成功,是因为整个请求周期都在book-servlet的上下文内完成。
2. 跨Servlet上下文的Session共享问题
虽然同一个Web应用下的多个DispatcherServlet默认共享同一个HttpSession,但如果你的Servlet映射路径配置导致Session Cookie的路径不匹配,就会出现两个上下文使用独立Session的情况:
- 当请求
/book/review时,Web容器会设置Session Cookie的路径为/book(根据Servlet映射路径); - 当重定向到
/report/update时,浏览器会检查Cookie路径,发现/book路径的Cookie不匹配/report路径,因此不会携带该Cookie; - 此时
report-servlet会创建一个全新的HttpSession,ReportController存入的report属性会被放在这个新Session中,而你检查的可能是原来book-servlet对应的Session,所以误以为没有存入。
3. 连续重定向的额外影响
你的ReportController的show方法返回重定向到/report/done,这又是一次客户端跳转。如果/report/done同样被report-servlet处理,那么新Session中的report属性应该是存在的,但如果Cookie路径问题导致Session不共享,后续请求也无法获取到这个属性。
- 验证Session是否共享:在两个控制器的
show方法中打印request.getSession().getId(),如果ID不同,说明Session完全独立,问题出在Cookie路径配置; - 统一Session Cookie路径:在web.xml中配置全局的Session Cookie路径为
/,确保所有请求都携带同一个Session Cookie:<session-config> <cookie-config> <path>/</path> </cookie-config> </session-config> - 替代方案:使用
HttpSession直接操作:如果跨DispatcherServlet共享属性是业务需求,建议直接通过HttpSession对象来存储和读取属性,绕过@SessionAttributes的上下文限制:// 在BookController中 @GetMapping("/book/review") public String show(HttpSession session) { session.setAttribute(BookController.COMMAND_NAME, getBook()); return "redirect:/report/update"; } // 在ReportController中 @GetMapping("/report/update") public String show(HttpSession session) { session.setAttribute(ReportController.COMMAND_NAME, getReport()); return "redirect:/report/done"; }
内容的提问来源于stack exchange,提问作者Subrata nath

