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.mzph.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…