RequestContextHolder 與 HttpServletRequest 的聯系

1. 什么是 RequestContextHolder?

  • RequestContextHolderSpring 框架 提供的一個工具類,用于在當前線程中存儲和獲取與請求相關的上下文信息。
  • 它是基于 ThreadLocal 實現的,能夠保證每個線程獨立存儲和訪問請求信息。

與 HttpServletRequest 的關系:

HttpServletRequest

  • 是標準的 Servlet API 提供的類,用于表示一個 HTTP 請求。
  • 在 Controller 方法中,我們通常通過參數注入來獲取它:
    @GetMapping("/example")
    public String example(HttpServletRequest request) {String param = request.getParameter("name");return "Parameter: " + param;
    }
    

RequestContextHolder

  • 是 Spring 對請求上下文的封裝。
  • 它的核心是通過 RequestAttributes(Spring 自定義的接口)來間接操作 HttpServletRequest,從而獲取請求信息。
  • 它的最大優勢是:在 Service 層、過濾器、攔截器 等不能直接注入 HttpServletRequest 的地方,也能獲取請求信息。

2. RequestContextHolder 與 HttpServletRequest 的聯系

核心聯系

  • RequestContextHolder 不會直接持有 HttpServletRequest,但它持有與請求相關的上下文信息。
  • 這個上下文信息是通過 RequestAttributes 實現的,而 ServletRequestAttributes 是它的一個實現類,封裝了 HttpServletRequestHttpServletResponse

示意圖

HttpServletRequest  ↓  
ServletRequestAttributes(封裝 HttpServletRequest)  ↓  
RequestContextHolder(通過 ThreadLocal 保存 ServletRequestAttributes)
  • 當 Spring 處理請求時,它會將 HttpServletRequest 封裝成 ServletRequestAttributes,然后綁定到當前線程的 ThreadLocal 中。
  • RequestContextHolder 就是通過 ThreadLocal 拿到 ServletRequestAttributes,再從中獲取 HttpServletRequest

3. RequestContextHolder 的工作原理

綁定請求上下文

Spring 在處理 HTTP 請求時,會自動把 HttpServletRequest 封裝成 ServletRequestAttributes 并綁定到線程中:

ServletRequestAttributes attributes = new ServletRequestAttributes(request);
RequestContextHolder.setRequestAttributes(attributes);

獲取請求對象

我們可以通過 RequestContextHolder 拿到請求上下文,進一步獲取 HttpServletRequest

ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();

總結RequestContextHolder 是一個中間橋梁,它通過 ServletRequestAttributes 間接地連接到 HttpServletRequest


4. RequestContextHolder 提供的主要方法

獲取請求上下文

getRequestAttributes():獲取當前線程保存的請求上下文。

示例

RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
if (attributes instanceof ServletRequestAttributes) {HttpServletRequest request = ((ServletRequestAttributes) attributes).getRequest();System.out.println("請求參數:" + request.getParameter("name"));
}
  • 返回類型是 RequestAttributes,需要強轉為 ServletRequestAttributes 才能拿到 HttpServletRequest

Spring 設計 RequestAttributes 作為一個 通用接口,這樣可以支持不同類型的請求上下文,而不僅僅是 HTTP 請求。

  • RequestAttributes:定義了請求上下文的通用方法,不依賴于特定類型的請求。
  • ServletRequestAttributesRequestAttributes 的一個具體實現,專門封裝 Servlet 環境 下的 HttpServletRequestHttpServletResponse

為什么需要強制轉換?

因為 RequestAttributes 接口 是通用的,它不知道自己具體是什么請求類型(例如 Servlet 請求、Portlet 請求等)。

  • RequestAttributes 只提供了通用方法,比如存儲和獲取請求屬性。
  • ServletRequestAttributes 提供了專門的方法,比如 getRequest()getResponse(),用于獲取 HttpServletRequestHttpServletResponse

currentRequestAttributes()

  • getRequestAttributes() 類似,但如果沒有請求上下文,它會拋出異常。

RequestContextHolder 提供的方法

方法作用
getRequestAttributes()獲取當前線程綁定的 RequestAttributes,如果沒有返回 null
currentRequestAttributes()獲取當前線程的 RequestAttributes,如果沒有會拋出異常。
setRequestAttributes(RequestAttributes)手動將 RequestAttributes 綁定到當前線程。適用于手動設置上下文的場景。
resetRequestAttributes()清除當前線程綁定的 RequestAttributes,防止內存泄漏。
setRequestAttributes(RequestAttributes, boolean inheritable)支持將請求上下文傳遞給子線程。inheritable = true 表示上下文可繼承。

5. 使用場景及代碼示例

場景 1:在 Service 層獲取 HttpServletRequest

通常情況下,Service 層不能直接訪問 HttpServletRequest,但可以通過 RequestContextHolder 獲取:

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;public class RequestUtil {public static HttpServletRequest getCurrentRequest() {ServletRequestAttributes attributes =(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();return attributes != null ? attributes.getRequest() : null;}
}

使用

public void printRequestParam() {HttpServletRequest request = RequestUtil.getCurrentRequest();if (request != null) {String name = request.getParameter("name");System.out.println("請求參數 name:" + name);} else {System.out.println("無法獲取 HttpServletRequest");}
}

場景 2:在異步線程中傳遞請求上下文

默認情況下,Spring 的請求上下文不會自動傳遞給新線程。需要手動設置:

import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;public class AsyncRequestExample {public void processInAsyncThread() {// 獲取當前請求上下文RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();new Thread(() -> {try {// 綁定請求上下文到新線程RequestContextHolder.setRequestAttributes(attributes, true);// 獲取 HttpServletRequestHttpServletRequest request =((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();System.out.println("異步線程中獲取請求參數:" + request.getParameter("name"));} finally {// 清理請求上下文,防止內存泄漏RequestContextHolder.resetRequestAttributes();}}).start();}
}

場景 3:過濾器或攔截器中設置請求上下文

在自定義的過濾器中手動設置請求上下文:

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;public class CustomFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {// 手動設置上下文RequestContextHolder.setRequestAttributes(new ServletRequestAttributes((HttpServletRequest) request));try {chain.doFilter(request, response);} finally {// 清理上下文,防止內存泄漏RequestContextHolder.resetRequestAttributes();}}
}

6. RequestContextHolder 的注意事項

  • 必須在請求線程中使用

    • RequestContextHolder 依賴于 ThreadLocal,只能在處理請求的線程中使用。
    • 如果在非 Web 環境或沒有 HTTP 請求的線程中調用,會返回 null 或拋出異常。
  • 異步線程問題

    • 異步線程無法自動繼承父線程的請求上下文,必須手動通過 setRequestAttributes 傳遞。
  • 內存泄漏風險

    • 在使用線程池時,如果不清理請求上下文(resetRequestAttributes),可能會導致內存泄漏。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/63270.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/63270.shtml
英文地址,請注明出處:http://en.pswp.cn/web/63270.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SpringBoot配置和啟動

1.內部配置加載順序: 加載規則 加載順序和優先級與配置文件所在路徑有關優先級高的配置會覆蓋優先級低的配置,配置文件會全部加載,遇到相同的配置高優先級覆蓋低優先級命令行參數 -spring.config.location 自定義配置文件路徑,可…

【視頻生成模型】——Hunyuan-video 論文及代碼講解和實操

🔮混元文生視頻官網 | 🌟Github代碼倉庫 | 🎬 Demo 體驗 | 📝技術報告 | 😍Hugging Face 文章目錄 論文詳解基礎介紹數據預處理 (Data Pre-processing)數據過濾 (Data Filtering)數據標注 (Data…

52 基于單片機的超聲波、溫濕度、光照檢測分階段報警

目錄 一、主要功能 二、硬件資源 三、程序編程 四、實現現象 一、主要功能 1.通過DHT11模塊讀取環境溫度和濕度: 2.將濕度、障礙物距顯示在lcd1602上面,第一行顯示溫度和濕度,格式為:xxCyy%,第二行顯示超聲波傳感器測得的距離,格式為:Di…

大數據與AI:從分析到預測的躍遷

引言:數據時代的新紀元 從每天的社交分享到企業的運營決策,數據早已成為現代社會不可或缺的資源。我們正置身于一個數據爆炸的時代,數以億計的信息流實時生成,為人類帶來了前所未有的洞察能力。然而,數據的價值并不僅限…

3D視覺[一]3D計算機視覺

3D視覺[一]3D計算機視覺 3D計算機視覺概述 像機標定 文章目錄 3D視覺[一]3D計算機視覺前言一、人類視覺二、計算機視覺2.1 計算機視覺的研究目的2.2 計算機視覺的研究任務2.3 計算機視覺的研究方法2.4 視覺計算理論2.5 馬爾框架中計算機視覺表達的四個層次2.5.1 圖像&#xff…

OpenCV目標檢測 級聯分類器 C++實現

一.目標檢測技術 目前常用實用性目標檢測與跟蹤的方法有以下兩種: 幀差法 識別原理:基于前后兩幀圖像之間的差異進行對比,獲取圖像畫面中正在運動的物體從而達到目標檢測 缺點:畫面中所有運動中物體都能識別 舉個例子&#xf…

QT從入門到精通(二) ——信號與槽機制

Qt 的信號與槽機制(Signal and Slot)是 Qt 框架 中用于對象間通信的核心機制之一。它允許對象之間進行松耦合的事件驅動式通信,尤其適合 GUI 應用程序 中的事件處理。 1. 基本概念 信號 (Signal) 當對象的狀態發生變化時,它會發…

如何使用git新建本地倉庫并關聯遠程倉庫的步驟(詳細易懂)

一、新建本地倉庫并關聯遠程倉庫的步驟 新建本地倉庫 打開終端(在 Windows 上是命令提示符或 PowerShell,在 Linux 和Mac上是終端應用),進入你想要創建倉庫的目錄。例如,如果你想在桌面上創建一個名為 “my - project”…

1Panel應用推薦:MaxKB開源知識庫問答系統

1Panel(github.com/1Panel-dev/1Panel)是一款現代化、開源的Linux服務器運維管理面板,它致力于通過開源的方式,幫助用戶簡化建站與運維管理流程。為了方便廣大用戶快捷安裝部署相關軟件應用,1Panel特別開通應用商店&am…

element plus的table組件,點擊table的數據是,會出現一個黑色邊框

在使用 Element Plus 的 Table 組件時,如果你點擊表格數據后出現了一個黑色邊框,這通常是因為瀏覽器默認的焦點樣式(outline)被觸發了。如圖: 你可以通過自定義 CSS 來隱藏這個黑色邊框,代碼如下&#xff1…

瀧羽sec學習打卡-brupsuite7搭建IP炮臺

聲明 學習視頻來自B站UP主 瀧羽sec,如涉及侵權馬上刪除文章 筆記的只是方便各位師傅學習知識,以下網站只涉及學習內容,其他的都 與本人無關,切莫逾越法律紅線,否則后果自負 關于brupsuite的那些事兒-Brup-IP炮臺搭建 搭建炮臺服務端安裝zmap1、更新系統和安裝基礎依賴&#xff…

赫布定律 | 機器學習 / 反向傳播 / 經驗 / 習慣

注:本文為 “赫布定律” 相關文章合輯。 未整理。 赫布定律 Hebb‘s law 馥墨軒 2021 年 03 月 13 日 00:03 1 赫布集合的基本定義 唐納德?赫布(Donald Hebb)在 1949 年出版了《行為的組織》(The Organization of Behavior&a…

各個數據庫優劣勢對比

1.關系型數據庫(RDBMS) 優勢: ? 數據一致性:通過嚴格的事務處理和ACID(原子性、一致性、隔離性、持久性)特性,確保數據的一致性和完整性。 ? 易于理解和使用:關系型數據庫的表結構…

Excel中如何消除“長短款”

函數微調可以可以實施,簡單且易于操作的氣球🎈漲縮更妙。 (筆記模板由python腳本于2024年12月17日 06:19:13創建,本篇筆記適合用Excel操作數據的coder翻閱) 【學習的細節是歡悅的歷程】 Python 官網:https://www.python.org/ Fre…

Jdk1.7到Jdk1.8 HashMap 發生了什么變化(底層)

從JDK 1.7到JDK 1.8,HashMap在底層實現上發生了顯著的變化, 主要體現在數據結構、鏈表插入方式、哈希算法、擴容機制以及并發性方面。 以下是具體的變化點: 1. 數據結構的變化 JDK 1.7:HashMap的底層數據結構是數組單向鏈表。…

RJ45 網線線序、E1線線序、2B+d線序

1、RJ45 網線線序 線序排列如下: T568A線序:綠白—1,綠—2,橙白—3,藍—4,藍白—5, 橙—6,棕白—7,棕—8 T568B線序:橙白—1,橙—2&#xff0c…

FreeBSD安裝教程

FreeBSD 是一個功能強大且可靠的開源 UNIX 操作系統,適合服務器和桌面環境。本文將介紹如何安裝 FreeBSD,從系統準備到基礎設置,為你快速上手提供幫助。 一、準備工作 1. 硬件要求 CPU:支持 x86 或 AMD64 架構的處理器。 內存&a…

Fortify_SCA_v24.2.0

前言 Fortify SCA 支持豐富的開發環境、語言、平臺和框架,可對開發與生產混合環境進行安全檢查。25 種編程語言 超過 911,000 個組件級 API 可檢測超過 961 個漏洞類別 支持所有主流平臺、構建環境和 IDE。 Fortify SCA是一款商業軟件,價格較為昂貴&am…

MyBatis框架的入門

目錄 MyBatis第一章:框架的概述1. MyBatis框架的概述 第二章:MyBatis的入門程序1. 創建數據庫和表結構2. MyBatis的入門步驟 MyBatis 第一章:框架的概述 1. MyBatis框架的概述 MyBatis是一個優秀的基于Java的持久層框架,內部對…

rust的axux框架開啟負載均衡和重啟自身的方法-會議簽到的調優

開啟負載均衡和重啟自身 更換axum后臺的意外解決的嘗試在caddy反代,使用負載均衡,加多一個節點axum主程序 ip映射信息做全局共享axum重啟自身刷新全局共享配置 前期剛實現了rust的后臺關鍵業務.結果出現了兩類大問題停止服務.在正用著的時候,出現很多意外,真是刺激… 更換axum…