异步线程中使用 request

文章讲述了在使用mybatis-plus项目时,如何在异步线程中处理来自主线程的request,涉及RequestContextHolder、HttpServletRequestWrapper的继承以及startAsync方法的使用以保持request的生命周期。
摘要由CSDN通过智能技术生成

由于项目使用的是 mybatis-plus 来自动帮我填充通用字段,而这些通用字段都是从 request 里面取 token 然后解析得来的。

所以我使用 异步的时候,我也需要使用主线程的 request。

最开始我是在主线程中用 RequestContextHolder.getRequestAttributes() 拿到 RequestAttributes ,然在子线程中在 set 进去。

我以为这样就完美解决了,后面发现在异步线程中还是无法使用 request。

通过了解 request 的机制。request 在主线程结束之后,会进行释放。而我上面的操作只是传递了 RequestAttributes ,而 request 还是使用的同一个。

所以我们需要复制一个 request 。但是 request 怎么复制。

request 是不好复制的,但是我们可以采用继承的方式。

首先继承 HttpServletRequestWrapper ,然后我们可以保存 request 的一些需要的值。然后重写一下 我们需要使用的一些 request 的方法,从我们自己保存的值去拿。然后我们只需要在子线程中使用我们自己的 request 就好了。

public class HttpRequestCopy extends HttpServletRequestWrapper {
    private Map<String,String> header;

    private Map<String,Object> attr;

    public HttpRequestCopy(HttpServletRequest request) {
        super(request);
        header = new HashMap<>();
        attr = new HashMap<>();
        Enumeration<String> headers = request.getHeaderNames();
        if (headers != null) {
            while (headers.hasMoreElements()) {
                String header = (String) headers.nextElement();
                this.header.put(header, request.getHeader(header));
            }
        }
    }

    @Override
    public String getHeader(String name) {
        return header.get(name);
    }
}

其实 request 是不建议在异步中使用的,所有 request 还提供了一个 startAsync() 方法,这个方法可以保证 request 不被回收。虽然可以异步,但是这个方法也会导致这个请求不会随着主线程的结束被响应。而是等程序调用 compete() 方法后才会释放 request 并响应请求。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
异步线程获取到的request为空,这是因为异步线程和原始的请求线程不在同一个线程异步线程无法直接访问原始的请求线程request对象。解决这个问题的方法有两种: 1. 使用Callable接口:可以将异步任务封装成一个Callable对象,并将原始的request对象作为参数传递给Callable对象。在异步任务,可以通过Future对象获取到Callable对象的返回值,从而获取到request对象。 代码示例: ``` @RestController public class MyController { @Autowired private AsyncService asyncService; @RequestMapping("/test") public String test(HttpServletRequest request) throws Exception { Callable<String> task = () -> { // 异步任务获取request对象 HttpServletRequest asyncRequest = AsyncRequestContextHolder.getRequest(); // 处理业务逻辑 return "success"; }; Future<String> future = asyncService.execute(task); String result = future.get(); return result; } } @Service public class AsyncService { @Autowired private AsyncTaskExecutor taskExecutor; public <T> Future<T> execute(Callable<T> task) { AsyncRequestContextCallable<T> callable = new AsyncRequestContextCallable<>(task); return taskExecutor.submit(callable); } } public class AsyncRequestContextCallable<T> implements Callable<T> { private final Callable<T> task; private final HttpServletRequest request; public AsyncRequestContextCallable(Callable<T> task) { this.task = task; this.request = AsyncRequestContextHolder.getRequest(); } @Override public T call() throws Exception { AsyncRequestContextHolder.setRequest(request); try { return task.call(); } finally { AsyncRequestContextHolder.resetRequest(); } } } public class AsyncRequestContextHolder { private static final ThreadLocal<HttpServletRequest> requestHolder = new ThreadLocal<>(); public static void setRequest(HttpServletRequest request) { requestHolder.set(request); } public static HttpServletRequest getRequest() { return requestHolder.get(); } public static void resetRequest() { requestHolder.remove(); } } ``` 2. 使用ServletRequestAttributes:可以使用Spring提供的ServletRequestAttributes类来获取request对象。这个类是一个请求属性的存储器,可以在任何线程存储和获取请求属性。在异步任务,可以通过ServletRequestAttributes来获取到原始的request对象。 代码示例: ``` @RestController public class MyController { @Autowired private AsyncService asyncService; @RequestMapping("/test") public String test(HttpServletRequest request) throws Exception { Callable<String> task = () -> { // 异步任务获取request对象 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest asyncRequest = attributes.getRequest(); // 处理业务逻辑 return "success"; }; Future<String> future = asyncService.execute(task); String result = future.get(); return result; } } @Service public class AsyncService { @Autowired private AsyncTaskExecutor taskExecutor; public <T> Future<T> execute(Callable<T> task) { return taskExecutor.submit(() -> { RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); try { RequestContextHolder.setRequestAttributes(attributes, true); return task.call(); } finally { RequestContextHolder.resetRequestAttributes(); } }); } } ``` 以上两种方法都可以解决异步线程获取request对象为空的问题,具体选择哪种方法取决于具体的业务需求和开发习惯。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值