SpringMVC DeferedResult和servlet3.1 AsyncContext异步请求

 

先看一个简单的示例:html

 1 @RequestMapping("/getFuture")
 2 public Future<String> getFuture() {
 3     System.out.println(1);
 4     // 必须是ListenableFuture的子类,或者CompletionStage子类,或者是DeferredResult 不能是FutureTask
 5     // 如何返回CompletableFuture
 6     CompletableFuture<String> ftu2 = CompletableFuture.supplyAsync(() -> {
 7         try {
 8             // RequestContextHolder.setRequestAttributes(attributes); 
 9             // 使用ThreadLocal相关特性时,须要在外面先get
10             Thread.sleep(3000L);
11         } catch (InterruptedException e) {
12         } finally {
13             // RequestContextHolder.resetRequestAttributes();
14         }
15         return "THIS string";
16     }, es);
17 
18     //Future<String> future = executorService.submit(() -> { }); //返回值是FutureTask
19 
20     return ftu2;
21 }

 

 




客户端发起请求
===> DispatcherServlet根据返回值类型查找对应的handlar CallableMethodReturnValueHandler; DeferredResult,CallableFuture,ListenableFuture --> AsyncHandlerMethodReturnValueHandler
【Callable -->DeferredResultMethodReturnValueHandler】
===> Controller中返回Future对象给容器, 
org.springframework.web.context.request.async.WebAsyncManager#startDeferredResultProcessing处理Future结果的监听

===>
sleep3秒以后,Future完成后调用asyncWebRequest.dispatch() 从新发给Container,DispatcherServlet找到Message的序列化器将结果输出。DispatcherServlet.doService会进入两次!!!

异步线程的主要功能是:
业务处理耗较长(上面的sleep3)时,能够先返回Future对象释放Container的work线程, work线程能够接收更多的请求。等Future完成以后从新调用Container的另外一个work线程,输出response.

这里work线程能够是BIO中work线程, 也能够是NIO中work线程

不是全部的Future都能在异步线程中处理
https://www.cnblogs.com/dennyzhangdd/p/7010972.html


spring boot中配置container的work线程数量
server.tomcat.max-threads=5
server.tomcat.min-spare-threads=3
 
使用异步处理的优势:
增长系统吞吐量,对响应速度提升不大,可能还会下降
缺点:
线程关系复杂, 异步超时、异常日志拦截须要实现具体的Adapter接口,threadLocal很差清理

参考:《亿级流量架构核心技术》http://jinnianshilongnian.iteye.com/blog/2245925
Servlet3.1 规范
    tomcat线程配置 http://www.javashuo.com/article/p-zdpklgiu-bv.html


遗留问题: Future.get是何时调用的?
没有直接调用get。 ListenerableFuture, CompletableFuture任务完成以后都会触发回调

work1线程: 接收到请求---> DispatcherServlet--> return future -->WebAsyncManager#startDeferredResultProcessing
自定义的任务线程: CompletableFuture.postComplete以后调用 WebAsyncManager#setConcurrentResultAndDispatch
work2线程: dipatch ---> DispatcherServlet --> response.out


关于第二个任务线程
返回值是Callable时,调用WebAsyncManager#startCallableProcessing, 此时任务线程使用的是AsyncTaskExecutor
能够经过org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter#configureAsyncSupport设置自定义的AsyncTaskExecutor

返回值是DeferredResult,ListenableFuture (Spring提供),CompletableFuture(JDK自带)时,调用WebAsyncManager#startDeferredResultProcessing,此时任务线程池能够直接指定
@See CompletableFuture.supply(xxxTask, threadPool)

@RequestMapping("/callableTest")
public Callable<String> callableTest() {
    Callable<String> hello = () -> {
        // 此处不能设置线程池, WebAsyncManager中会使用AsyncSupportConfigurer的线程池
        System.out.println("===>" + Thread.currentThread().getName());
        return "HELLO";
    };
    return hello;
}
相关文章
相关标签/搜索