HttpServletRequest、HttpServletResponse、HttpSession 都是 請求級/會話級 對象:
而 Spring Bean 默認是 單例,容器啟動時實例化,應用關閉才銷毀。若直接注入,高併發下所有請求共用同一個 Request/Response 對象,會導致嚴重的線程安全問題與數據錯亂。
Spring MVC 會自動將當前請求相關對象注入到處理器方法參數中:
@Controller
public class MyController {
@GetMapping("/example")
public String handle(HttpServletRequest request,
HttpServletResponse response,
HttpSession session) {
// 直接使用,線程安全
String uid = request.getParameter("uid");
session.setAttribute("user", uid);
response.setHeader("X-Custom", "value");
return "viewName";
}
}
若在 Service、Util、Interceptor 等非控制器類中需要訪問,可使用 RequestContextHolder:
// 獲取當前請求的 HttpServletRequest
HttpServletRequest request = ((ServletRequestAttributes)
RequestContextHolder.getRequestAttributes()).getRequest();
// 獲取 HttpServletResponse (需配置 RequestContextListener 或 Filter)
HttpServletResponse response = ((ServletRequestAttributes)
RequestContextHolder.getRequestAttributes()).getResponse();
// 獲取 Session (建議從 request 獲取)
HttpSession session = request.getSession(false); // false 表示不自動創建
前提:在 web.xml 中註冊 RequestContextListener 或 Spring MVC 的 DispatcherServlet 已啟用 requestContextAttribute。
| 場景 | 推薦方式 |
|---|---|
| Controller 方法 | 方法參數直接聲明 |
| Interceptor / Filter | 方法參數或 RequestContextHolder |
| Service / Util / 異步線程 | 控制器層提取所需數據作為參數傳入,避免耦合 Web 層 |
理解生命週期差異,避免在單例 Bean 中持有請求級對象,是 Spring 開發的基本功。