SpringMVC DeferedResult和servlet3.1 AsyncContext异步请求
2024-09-07 19:04:56
先看一个简单的示例:
@RequestMapping("/getFuture")
public Future<String> getFuture() {
System.out.println(1);
// 必须是ListenableFuture的子类,或者CompletionStage子类,或者是DeferredResult 不能是FutureTask
// 如何返回CompletableFuture
CompletableFuture<String> ftu2 = CompletableFuture.supplyAsync(() -> {
try {
// RequestContextHolder.setRequestAttributes(attributes);
// 使用ThreadLocal相关特性时,需要在外面先get
Thread.sleep(3000L);
} catch (InterruptedException e) {
} finally {
// RequestContextHolder.resetRequestAttributes();
}
return "THIS string";
}, es); //Future<String> future = executorService.submit(() -> { }); //返回值是FutureTask return ftu2;
}
客户端发起请求
===> DispatcherServlet根据返回值类型查找对应的handlarAsyncHandlerMethodReturnValueHandler
CallableMethodReturnValueHandler; DeferredResult,CallableFuture,ListenableFuture -->
【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线程配置 https://www.cnblogs.com/kismetv/p/7806063.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;
}
最新文章
- ReadReadMe
- EF的入门使用 (电影管理)
- php比较时间戳与时间差计算函数( 实用)
- 从Java看跨平台的.NET需要些什么?
- SQL中CONVERT()函数用法详解
- [UNIX环境高级编程](第三版)中apue.h的问题
- 《JavaScript高级程序设计》 读书笔记(一)
- JBPM流程实例(PI)Process Instance
- 编写一个方法,输入DOM节点,返回包含所有父节点的一个数组
- TypeScript设计模式之组合、享元
- jmeter3.3测试需要登录的接口(java)
- MyBatis报错:Caused by: java.lang.NumberFormatException: For input string: ";XX";
- java项目----衣服购买
- redis 系列11 列表对象
- IntelliJ IDEA 注册码——亲测有效
- NIO完成网络通信(一)
- Service Mesh简介
- Mysql root账号general_log_file方法获取webshell
- 小学四则运算APP 第一个冲刺阶段 第三天
- 【LOJ】#2128. 「HAOI2015」数字串拆分
热门文章
- 【总结整理】js获取css的属性(内部,外部,内嵌(写在tag中))
- Border Layout
- cd命令无效
- 【摘自张宴的";实战:Nginx";】使用nginx的proxy_cache模块替代squid,缓存静态文件
- C语言-郝斌笔记-006排序及查找
- oracle错误汇总解决
- Luogu 3466 [POI2008]KLO-Building blocks
- Bulma 源码解析之 .columns 类
- C++面试笔记--宏定义
- android studio 程序员有福了—从layout自动生成viewholder类