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

做的网站不能放视频软件简约大气网站设计欣赏

做的网站不能放视频软件,简约大气网站设计欣赏,网站模版 蓝色,wordpress 抓别人数据📝 Part 2:Web 请求上下文 —— RequestContextHolder 与异步处理 在 Spring Web 开发中,请求级别的上下文管理是一个非常常见的需求。例如我们需要在整个 HTTP 请求生命周期中传递用户信息、traceId、租户标识等上下文数据。Spring 提供了 …

📝 Part 2:Web 请求上下文 —— RequestContextHolder 与异步处理

在 Spring Web 开发中,请求级别的上下文管理是一个非常常见的需求。例如我们需要在整个 HTTP 请求生命周期中传递用户信息、traceId、租户标识等上下文数据。Spring 提供了 RequestContextHolderRequestAttributes 接口来帮助我们实现这一目标。

本文将带你深入理解 RequestContextHolder 的原理、使用方式以及如何解决其在异步场景下的失效问题,并结合实际业务场景给出最佳实践。


一、RequestContextHolder 是什么?

RequestContextHolder 是 Spring MVC 提供的一个工具类,用于获取当前线程绑定的 RequestAttributes 对象。它本质上是基于 ThreadLocal 实现的。

public abstract class RequestContextHolder {private static final ThreadLocal<RequestAttributes> requestAttributesHolder = new ThreadLocal<>();...
}

通过这个对象,我们可以访问到当前 HTTP 请求中的各种属性(如 request、session、attributes 等)。


二、RequestAttributes 常用方法解析

RequestAttributes 是一个接口,定义了多个方法用于操作请求范围内的属性。

常用方法如下:

方法描述
setAttribute(String name, Object value, int scope)设置属性值,scope 可为 SCOPE_REQUESTSCOPE_SESSION
getAttribute(String name, int scope)获取指定作用域的属性值
removeAttribute(String name, int scope)移除属性
registerDestructionCallback(String name, Runnable callback)注册销毁回调,适用于需要清理资源的场景

示例代码:

// 设置请求级属性
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
requestAttributes.setAttribute("userId", "123", RequestAttributes.SCOPE_REQUEST);// 获取属性
String userId = (String) requestAttributes.getAttribute("userId", RequestAttributes.SCOPE_REQUEST);

三、典型使用场景

1. 在拦截器中设置上下文

@Component
public class UserContextInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String userId = request.getHeader("X-User-ID");if (userId != null) {RequestContextHolder.getRequestAttributes().setAttribute("userId", userId, RequestAttributes.SCOPE_REQUEST);}return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 清理上下文(可选)RequestContextHolder.resetRequestAttributes();}
}

2. 在 Controller 或 Service 层获取上下文

@RestController
public class UserController {@GetMapping("/user")public String getCurrentUser() {RequestAttributes attrs = RequestContextHolder.getRequestAttributes();String userId = (String) attrs.getAttribute("userId", RequestAttributes.SCOPE_REQUEST);return "Current User ID: " + userId;}
}

四、异步任务中上下文丢失问题

1. 为什么异步线程中无法访问到 RequestContextHolder?

因为 RequestContextHolder 内部是基于 ThreadLocal 实现的,而异步线程(如 CompletableFuture@Async、线程池等)属于新线程,无法继承主线程的 ThreadLocal 数据。

示例代码:
@GetMapping("/async")
public String asyncTest() {RequestContextHolder.getRequestAttributes().setAttribute("userId", "123", RequestAttributes.SCOPE_REQUEST);new Thread(() -> {try {// 这里会抛出 NullPointerExceptionString userId = (String) RequestContextHolder.getRequestAttributes().getAttribute("userId", RequestAttributes.SCOPE_REQUEST);} catch (Exception e) {e.printStackTrace(); // 报错:RequestAttributes is null}}).start();return "Check console for error.";
}

五、解决方案:TTL + RequestContextHolder

1. 手动拷贝上下文到子线程

最简单的方式是在启动异步任务前手动保存上下文,并在子线程中恢复:

RequestAttributes originalAttrs = RequestContextHolder.getRequestAttributes();new Thread(() -> {try {RequestContextHolder.setRequestAttributes(originalAttrs);String userId = (String) RequestContextHolder.getRequestAttributes().getAttribute("userId", RequestAttributes.SCOPE_REQUEST);System.out.println("User ID in thread: " + userId);} finally {RequestContextHolder.resetRequestAttributes();}
}).start();

2. 使用 TransmittableThreadLocal 封装

更推荐的做法是使用 TransmittableThreadLocal 来自动完成上下文的跨线程传递。

你可以封装一个 TtlRequestContextHolder 类:

public class TtlRequestContextHolder {private static final TransmittableThreadLocal<RequestAttributes> contextHolder = new TransmittableThreadLocal<>();public static void set(RequestAttributes attributes) {contextHolder.set(attributes);}public static RequestAttributes get() {return contextHolder.get();}public static void reset() {contextHolder.remove();}
}

然后在拦截器中替换默认的 RequestContextHolder

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {RequestAttributes attrs = RequestContextHolder.getRequestAttributes();TtlRequestContextHolder.set(attrs);return true;
}@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {TtlRequestContextHolder.reset();
}

最后在异步任务中使用:

ExecutorService executor = TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(2));executor.submit(() -> {RequestAttributes attrs = TtlRequestContextHolder.get();String userId = (String) attrs.getAttribute("userId", RequestAttributes.SCOPE_REQUEST);System.out.println("User ID in thread: " + userId);
});

六、Spring Boot 中的 @Scope("request") Bean

你还可以利用 Spring 的作用域机制创建请求级别的 Bean,这样可以在整个请求生命周期内共享上下文。

示例:

@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestContext {private String userId;public String getUserId() {return userId;}public void setUserId(String userId) {this.userId = userId;}
}

在拦截器中注入并设置:

@Autowired
private RequestContext requestContext;@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String userId = request.getHeader("X-User-ID");requestContext.setUserId(userId);return true;
}

七、总结建议

场景推荐方案
Web 请求内上下文共享RequestContextHolder + 拦截器
异步任务中访问上下文TTL + 自定义 TtlRequestContextHolder
多个组件间共享上下文@Scope("request") Bean
日志追踪MDC + TTL
分布式链路追踪Sleuth + Zipkin

📌 参考链接

  • Spring RequestContextHolder 官方文档
  • TransmittableThreadLocal GitHub
http://www.dtcms.com/a/397186.html

相关文章:

  • 刚做的网站搜全名查不到自建网站网址
  • 沧州免费建站后端开发工程师前景
  • 济南网站建设正规公司哪家好科技与狠活是什么梗
  • 校园网站开发的目的山西住房与城乡建设厅网站
  • 怎么做自己地网站郑州做网站茂睿科技
  • 西安网站建设公司咪豆商贸公司网站模板
  • 徐州seo网站推广青岛建站模板制作
  • 西安做网站一般多少钱兰州新区装修公司哪家好
  • 中国住房和城乡建设网网站中小企业网络营销论文
  • 温州网站运营今天31个省新增最新消息
  • 服装市场网站建设营销网
  • 阿里云云主机做网站什么是网站流量优化
  • 建设网站客户资源从渠道来河北港网站建设
  • 中国做国际期货最大的网站做公司网站需要服务器吗
  • 10_10_微信里网站怎么做的在线教育平台系统搭建
  • 宜宾网站制作公司mvc做网站用的多不多
  • 网站建设经济可行性网站建设数据库系统
  • 网站开发技术期中试题网站建设对帮助信息的设置
  • 寻花问柳专注做一家男人喜欢的网站施工企业费用预算的编制的内容包括
  • 安徽网站建设seo优化关键词优化排名软件哪家好
  • 苏州做网站建设网站建设经典文章
  • dedecms 网站根目录招工网站怎么做
  • 网站开发发帖语言网站建设费用分类
  • 装修网站设计平台建设厅考试网站
  • CP网站建设搭建需要多少钱常州设计公司
  • 专业定制网站设计网站怎样上传到空间
  • 综合网站系统自己做的网站跳转到购彩大厅
  • 最早做美食团购的网站江苏省建设工程协会网站
  • 镇江建设工程质量监督局网站外国网站学习做任务 升级
  • 哈尔滨旅游团购网站建设网站建设合约具体内容