请求异步处理

请求异步处理

当我们使用Spring Boot进行web开发时,默认使用Tomcat作为Servlet的容器,而Tomcat的线程池大小默认为200,如果我们的处理流程很长,就可能因为请求过多而造成线程池里的线程占满,这时候可以使用异步线程

返回Callable接口

在Spring MVC中,如果我们的请求处理方法返回一个Callable接口,则会开启异步线程功能,主线程接收到请求,然后把处理交给副线程处理,这样主线程就可以空闲出来去处理别的请求

当副线程处理完成后,再获取到副线程的处理结果,然后返回给前端

@RestController
public class MyController {

    @RequestMapping("/test")
    public Callable<String> test() {
        System.out.println("主线程" + Thread.currentThread());
        return () -> {
            System.out.println("副线程" + Thread.currentThread());
            return "SUCCESS";
        };
    }
}

发送一个测试请求,可以获取到副线程中的返回值

在这里插入图片描述

在后台也可以看到打印的线程信息,接收请求的线程和处理的线程是两个不一样的线程

在这里插入图片描述

那么接受请求和处理的请求是由两个线程完成的,在返回数据的时候又是怎么能得到处理线程的数据,并且返回给相对应的请求呢?在Spring MVC的官方文档中有答案

在这里插入图片描述

  • Spring MVC提交CallableTaskExecutor一个单独的线程中进行处理
  • 同时,DispatcherServlet和所有过滤器退出Servlet容器线程,但响应保持打开状态
  • 当副线程执行完成时,Spring MVC将请求分派回Servlet容器以完成处理。
  • 再次调用DispatcherServlet,并且返回副线程的处理结果

如果我们添加一个拦截器,就会发现拦截器拦截了两次请求

public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("执行前置处理方法");
        System.out.println("拦截到的请求" + request.getRequestURI());
        return true;
    }
}

在这里插入图片描述

这是因为再次调用DispatcherServlet并恢复原来的响应时,又被拦截器拦截到了

使用DeferredResult类

使用DeferredResult类,也可以实现异步处理,但是效果不同,它可以让处理请求的线程一直等待,直到DeferredResult类在另外的某处地方被处理并设置了返回值,这时候才将返回值返回给前端

我们用一个队列来保存DeferredResult对象,模拟请求的延时处理,在/test请求中产生一个DeferredResult对象,而在/handle请求中处理这个对象,这时候/test请求才会得到响应

@RestController
public class MyController {

    private static final Queue<DeferredResult<String>> queue = new LinkedList<>();

    @RequestMapping("/test")
    public DeferredResult<String> test() {
        DeferredResult<String> result = new DeferredResult<>();
        queue.add(result);
        return result;
    }

    @RequestMapping("/handle")
    public String handle() {
        DeferredResult<String> result = queue.poll();
        result.setResult("done");
        return "success";
    }
}

首先我们发送/test请求,浏览器一直等待响应

在这里插入图片描述

这时候我们再发送/handle请求,可以发现此前的/test请求拿到了返回值

在这里插入图片描述

在这里插入图片描述

我们还可以在构造DeferredResult对象的时候,使用构造方法设置处理的超时时间和超时时返回的结果

@RestController
public class MyController {
  
    @RequestMapping("/test")
    public DeferredResult<String> test() {
        DeferredResult<String> result = new DeferredResult<>(3000L, "fail");
        queue.add(result);
        return result;
    }
}

异步拦截器

使用异步拦截器,可以在请求方法异步执行时执行拦截方法

使用方法只需要创建自定义拦截器并实现AsyncHandlerInterceptor接口,重写afterConcurrentHandlingStarted方法,方法中的逻辑就会在请求方法异步执行时执行

最后需要在Spring MVC的web配置中注册拦截器,方法与普通的拦截器一样

public class MyInterceptor implements AsyncHandlerInterceptor {

    @Override
    public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("执行异步拦截器");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值