Spring 4.x.x+Tomcat 8.x.x下Web用户会话串户问题求助
这种会话串用的问题在该技术组合中并不少见,且仅Web端出现、APP端正常的情况,通常和Web端的请求处理上下文、会话配置或线程安全实现有关,以下是核心排查方向:
单例Bean/静态变量的线程安全问题
这是最常见的原因:如果你的代码里把用户信息(比如当前登录用户ID、账户对象)存在了静态变量里,或者存在单例Bean的成员变量中,多线程并发请求时,不同用户的请求会覆盖这些共享变量,直接导致串号。另外,若使用ThreadLocal存储用户上下文,一定要在请求结束时调用remove()清理——Tomcat会复用线程池中的线程,残留的ThreadLocal值会被下一个请求继承。Tomcat会话配置异常
检查Tomcat的context.xml,如果配置了自定义的Manager(比如分布式会话的实现),确认其线程安全和会话同步逻辑是否正确。如果是单节点部署,默认的内存会话也可能因为Tomcat的会话ID生成逻辑被修改、或者Cookie配置错误导致会话ID冲突——比如Web端的Cookie路径设置过宽,不同域名/子域名的请求共享了同一个会话Cookie。Spring Security上下文泄漏
若使用Spring Security,检查SecurityContextHolder的策略配置,绝对不能设置为MODE_GLOBAL(全局共享上下文)。另外,Web端如果有异步请求处理,要确保异步线程能正确继承或重置SecurityContext,否则异步任务会复用之前用户的上下文。视图层的状态共享问题
比如JSP中使用<%! %>声明的变量是类级别,会被所有请求共享;Thymeleaf等模板引擎中如果错误地将用户信息绑定到全局上下文,也会导致串号。
快速验证步骤
- 复现问题时,在请求入口(比如拦截器、Controller方法)打印
request.getSession().getId()和当前用户ID,确认会话ID和用户是否对应——如果同一个会话ID出现不同用户,说明会话存储有问题;如果不同会话ID却拿到同一个用户信息,说明上下文变量被共享了。 - 临时关闭Tomcat的线程池复用(修改
server.xml中Connector的maxThreads和minSpareThreads为相同值,或者禁用线程池),看问题是否消失,以此验证是否是ThreadLocal残留导致的。 - 单节点部署测试,排除多节点会话同步的干扰。
内容的提问来源于stack exchange,提问作者being_ethereal

