Spring控制器类变量未重新初始化问题咨询
Spring控制器类变量未重新初始化问题咨询
Hey Lee, 我来帮你理清楚这个问题的根源~
你之所以遇到和预期不符的情况,核心原因是Spring中@RestController默认是单例模式——也就是说,你的LoginController只会被创建一次,在整个应用的生命周期里都会复用这同一个实例。而你定义的sessionMap作为类的成员变量,自然也是全局共享的,不会在每次调用API时重新初始化。
结合你的操作场景具体分析:
- 当你第一次调用
/login?name=Jay时,当前请求会话的ID被作为key,Jay作为value存入了这个全局的sessionMap中; - 之后调用
/myName时,用同一个会话ID去map中取值,自然能拿到之前存储的Jay,所以接口返回了这个值。
而你期望/myName返回null,本质是误以为每次请求都会新建一个LoginController实例,导致sessionMap被重新初始化(变成空集合),但实际Spring的控制器实例并不会随请求重建。
解决方案推荐
其实你已经在方法中注入了HttpSession,完全可以直接利用它来存储会话级别的用户信息,不需要自己维护sessionMap,代码修改如下:
package com.example.study; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpSession; @RestController public class LoginController { @GetMapping("/login") public String login(HttpSession session, @RequestParam String name){ // 直接将名字存入当前会话 session.setAttribute("name", name); return "saved"; } @GetMapping("/myName") public String myName(HttpSession session){ // 从当前会话中取出名字 String myName = (String) session.getAttribute("name"); return myName; } }
这样每个会话的信息都是相互隔离的,Spring会自动帮你管理会话的生命周期,既安全又省心。
如果一定要自己维护全局map(非常不推荐,因为单例环境下多线程并发访问会有线程安全问题,还会导致内存占用持续增加),那你需要手动清空sessionMap或者处理键值对的过期逻辑,但这种做法完全没必要,用HttpSession是更符合SpringWeb设计的方案。
备注:内容来源于stack exchange,提问作者Lee Soobin
相关产品推荐
相关产品推荐

