当前位置: 首页 > news >正文

Springboot之RequestContextHolder 学习笔记

1. 核心作用


RequestContextHolder 是 Spring 框架中用于管理当前线程请求上下文的工具类。它的主要功能包括:
存储请求上下文:通过 ThreadLocal 存储与当前线程绑定的 RequestAttributes 对象(如 ServletRequestAttributes)。
全局访问点:提供静态方法,允许任意层代码(如 Service 或 DAO 层)无需显式传递 HttpServletRequest 即可获取当前请求信息。
 


2. 核心字段

private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
    new NamedThreadLocal<>("Request attributes");

private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder =
    new NamedInheritableThreadLocal<>("Request context");
  • requestAttributesHolder:

使用普通的 ThreadLocal,确保每个线程都有独立的 RequestAttributes 实例。
默认情况下,子线程无法访问父线程的 ThreadLocal 数据。

  • inheritableRequestAttributesHolder:

使用 InheritableThreadLocal,允许子线程继承父线程的 RequestAttributes。
适用于异步任务或需要跨线程传递请求上下文的场景。

3. 核心方法


(1) 设置请求属性

public static void setRequestAttributes(@Nullable RequestAttributes attributes, boolean inheritable) {
    if (attributes == null) {
        resetRequestAttributes();
    } else {
        if (inheritable) {
            inheritableRequestAttributesHolder.set(attributes);
            requestAttributesHolder.remove();
        } else {
            requestAttributesHolder.set(attributes);
            inheritableRequestAttributesHolder.remove();
        }
    }
}

逻辑说明:
如果 attributes 为 null,调用 resetRequestAttributes() 清空当前线程的请求上下文。
根据 inheritable 参数决定将 attributes 存入普通 ThreadLocal 或可继承的 ThreadLocal。
确保两个 ThreadLocal 不会同时持有数据,避免冲突。

(2) 获取请求属性

@Nullable
public static RequestAttributes getRequestAttributes() {
    RequestAttributes attributes = requestAttributesHolder.get();
    if (attributes == null) {
        attributes = inheritableRequestAttributesHolder.get();
    }
    return attributes;
}

逻辑说明:
首先尝试从普通 ThreadLocal 中获取 RequestAttributes。
如果未找到,则尝试从可继承的 ThreadLocal 中获取。


(3) 清理请求属性

public static void resetRequestAttributes() {
    requestAttributesHolder.remove();
    inheritableRequestAttributesHolder.remove();
}

逻辑说明:
清空当前线程的 ThreadLocal 数据,防止内存泄漏。
 

4. 设计思想


(1) 线程隔离

使用 ThreadLocal 实现线程级别的数据隔离,确保不同线程之间的请求上下文互不干扰。
在 Web 应用中,每个 HTTP 请求都会分配一个独立的线程,RequestContextHolder 利用这一特性来管理请求上下文。


(2) 全局访问

提供静态方法(如 getRequestAttributes()),让任意层代码都能方便地获取当前请求上下文。
解耦了业务代码与 Servlet API,提升代码的可测试性和灵活性。

(3) 异步支持

通过 InheritableThreadLocal 支持子线程继承父线程的请求上下文,适应异步任务场景。

 
5. 使用场景

(1) 获取当前请求对象

ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
    HttpServletRequest request = attributes.getRequest();
    String paramValue = request.getParameter("paramName");
}

 在非 Controller 层(如 Service 层)中获取当前请求的参数或 Header。


(2) 异步任务中传递请求上下文

RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
CompletableFuture.runAsync(() -> {
    RequestContextHolder.setRequestAttributes(attributes);
    // 异步任务中可以继续使用请求上下文
});

手动将父线程的 RequestAttributes 传递到子线程中。

6 Springboot设置/清除RequestContextHolder的时机

设置 RequestContextHolder 的时机

在请求进入时自动设置
Spring MVC 框架会在每次 HTTP 请求到达时,自动将当前请求的 HttpServletRequest 和 HttpServletResponse 绑定到 RequestContextHolder。
这是由 DispatcherServlet 完成的,通常不需要手动干预。
具体实现位于 org.springframework.web.context.request.RequestContextListener 或 org.springframework.web.filter.RequestContextFilter 中。
 

清除 RequestContextHolder 的时机

在请求结束时自动清除
Spring MVC 会在请求处理完成后,自动清除 RequestContextHolder 中的上下文信息。
这是通过 RequestContextListener 或 RequestContextFilter 在请求生命周期结束时完成的。

7. 注意事项

内存泄漏:

ThreadLocal 的生命周期与线程绑定,如果线程池中的线程被复用而未清理 ThreadLocal,可能导致内存泄漏。
Spring 的 RequestContextListener 或 DispatcherServlet 会在请求结束时自动清理 ThreadLocal。

异步任务:

默认情况下,异步任务不会继承父线程的 ThreadLocal 数据,需手动传递或启用 InheritableThreadLocal。

多线程环境:

在多线程环境中使用时,需特别注意请求上下文的传递和清理。

8. 总结

RequestContextHolder 是 Spring 框架中用于管理请求上下文的核心工具类,其设计充分利用了 ThreadLocal 的线程隔离特性,提供了简单易用的 API 来访问当前线程的请求上下文。通过合理的使用和清理,可以有效提升代码的灵活性和可维护性。

相关文章:

  • CANFD芯片在辐射环境中的技术演进
  • 【数学建模】最大最小值模型详解
  • Spring的基本用法
  • 服务器负载均衡
  • 机器学习——Numpy的神奇索引与布尔索引
  • JWT 认证机制
  • 第十三章 : Names in Templates_《C++ Templates》notes
  • 使用Gitee Go流水线部署个人项目到服务器指南
  • 稳定运行的以Oracle NoSQL数据库为数据源和目标的ETL性能变差时提高性能方法和步骤
  • 2025年01月03日微创网络(杭州银行外包)前端面试
  • 香橙派连接摄像头过程
  • 深入剖析 RocketMQ 的 ConsumerOffsetManager
  • RK3568开发笔记-egtouch触摸屏ubuntu系统屏幕校准
  • vue3中,通过获取路由上的token直接进入首页,跳过登录页面
  • 【前端 vue 或者麦克风,智能语音识别和播放功能】
  • python八股(—) --FBV,CBV
  • Python元组
  • LeetCode面试经典150题
  • 《网络安全等级测评报告模版(2025版)》
  • 点云分割方法
  • 上海“量子城市”先导应用场景落地曹杨社区,提供哪些服务?
  • 涨知识|没想到吧,体育老师强调的运动恢复方法是错的?
  • 治沙“异瞳”男生疑似摆拍,团队称合作12天多期视频为策划拍摄
  • 夜读丨古代有没有近视眼?
  • 菲护卫艇企图侵闯中国黄岩岛领海,南部战区:依法依规跟踪监视、警告驱离
  • 定位真核生物起源于约27.2亿年前,华东师大团队在《自然》发文