servlet异步请求的实现
作者:liushangzaibeijing 发布时间:2023-07-14 17:11:38
1、什么是servlet异步请求
Servlet 3.0 之前,一个普通 Servlet 的主要工作流程大致如下:
(1)、Servlet 接收到请求之后,可能需要对请求携带的数据进行一些预处理;
(2)、调用业务接口的某些方法,以完成业务处理;
(3)、根据处理的结果提交响应,Servlet 线程结束。
其中第二步处理业务逻辑时候很可以碰到比较耗时的任务,此时servlet主线程会阻塞等待完成业务处理,对于并发比较大的请求可能会产生性能瓶颈,则servlet3.0之后再此处做了调整,引入了异步的概念。
(1)、Servlet 接收到请求之后,可能需要对请求携带的数据进行一些预处理;
(2)、调用业务接口的某些方法过程中request.startAsync()请求,获取一个AsyncContext
(3)、紧接着servlet线程退出(回收到线程池),但是响应response对象仍旧保持打开状态,新增线程会使用AsyncContext处理并响应结果。
(4)、AsyncContext处理完成触发某些监听通知结果
2、Servlet异步请求示例
2.1、示例准备
本示例采用web.xml配置的形式,模拟场景为:笔者所在的it公司每周的工作内容,首先研发总监分配给产品、研发、测试相关的任务,布置完任务就出差(模拟请求响应),余下的各个小组进行自己任务操作(模拟的耗时操作),最终出周报完成任务(异步任务处理完成的通知)
git地址:https://github.com/liushangzaibeijing/spsm.git 分支:dev_async
2.2、实现自定义的Servlet
/**
* @ClassName AsyncServlet
* @Desc 自定义异步Servlet处理器
* @Author xieqx
* @Date 2020/12/9 15:38
**/
//通过注解的形式开始异步
@WebServlet(urlPatterns = "*.async",asyncSupported = true)
public class AsyncServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//开启异步支持
//异步管理上下文
resp.setCharacterEncoding("GBK");
PrintWriter writer = resp.getWriter();
writer.println("周工作任务布置开始");
AsyncContext asyncContext = req.startAsync();
asyncContext.start(new WeekTask(asyncContext));
//添加 * 处理完成监听
asyncContext.addListener(new AsyncListener() {
@Override
public void onComplete(AsyncEvent asyncEvent) throws IOException {
System.out.println("工作在"+new Date()+"处理完成");
}
@Override
public void onTimeout(AsyncEvent asyncEvent) throws IOException {
System.out.println("工作在"+new Date()+"处理超时");
}
@Override
public void onError(AsyncEvent asyncEvent) throws IOException {
System.out.println("工作在"+new Date()+"处理出错");
}
@Override
public void onStartAsync(AsyncEvent asyncEvent) throws IOException {
System.out.println("工作在"+new Date()+"处理开始");
}
});
writer.println("周工作任务布置完成");
writer.flush();
}
}
开启异步支持(默认异步支持不开启)有两种方式:
使用注解
web.xml配置
<servlet>
<servlet-name>asyncServlet</servlet-name>
<servlet-class>com.xiu.async.servlet.AsyncServlet</servlet-class>
<!-- 开启servlet的异步请求操作 -->
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>asyncServlet</servlet-name>
<url-pattern>*.async</url-pattern>
</servlet-mapping>
上述代码中通过request.startAsync()启动异步处理 返回一个异步上下文对象AsyncContext最终是使用该上下文对象来进行异步业务逻辑处理,其中有两个核心方法
asyncContext.start(new WeekTask(asyncContext)); 添加一个异步任务该任务是一个Runnable线程接口,这里就清晰了其实是servlet线程将处理任务交给另一个子线程,servlet直接返回从而达到提高系统吞吐量的作用。
对于异步请求可以我们需要获取其中的结果,所有这里提供了 * 模式添加事件监听AsyncListener
onComplete | 异步请求处理完成触发 前提示需要调用 asyncContext.complete()方法(因为程序也不知道什么时候任务算是调用完毕了) |
onTimeout | 异步请求处理超时触发,一般来说采用异步请求的任务都是比较耗时的任务,所以需要修改servlet默认的超时时间(修改的长一点) |
onError | 异步处理错误的时候触发 |
onStartAsync | 异步处理开始的时候触发即为request.startAsync(),因为添加 * 在startAsync()方法后,所以第一个启动是无法触发该监听的 |
这里异步处理只是简单的打印了相关日志,不过真实的业务场景中可以写复杂的业务处理逻辑。
2.3、异步任务
这里提供相关的异步操作是实现runnable的线程实现类,同时这里提供了相关Job,PmJob(产品任务),RDJob(研发任务),TestJob(测试任务),每个任务模拟了10秒的耗时任务。
/**
* @ClassName WeekTask
* @Desc 每周任务
* @Author xieqx
* @Date 2020/12/10 9:36
**/
public class WeekTask implements Runnable {
private List<Job> jobs = null;
private AsyncContext asyncContext = null;
//这里初始化产品任务PmJob、研发任务RDJob 测试任务TestJob
public WeekTask(AsyncContext asyncContext) {
this.asyncContext = asyncContext;
jobs = new ArrayList<>();
PmJob pmJob = new PmJob();
RDJob rdJob = new RDJob();
TestJob testJob = new TestJob();
jobs.add(pmJob);
jobs.add(rdJob);
jobs.add(testJob);
}
@Override
public void run() {
for(Job job:jobs){
job.execute();
}
System.out.println("周任务工作完成");
//job执行完成后通知
asyncContext.complete();
}
}
PmJob
/**
* @ClassName PmTask
* @Desc 产品经理任务
* @Author xieqx
* @Date 2020/12/9 16:03
**/
public class PmJob implements Job {
@Override
public void execute() {
System.out.println("产品经理开评审会议");
try {
Thread.sleep(10);
System.out.println("模拟需求评审会议...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
RDJob
/**
* @ClassName PmTask
* @Desc 研发任务
* @Author xieqx
* @Date 2020/12/9 16:03
**/
public class RDJob implements Job {
@Override
public void execute() {
System.out.println("程序猿开始开发");
try {
Thread.sleep(10);
System.out.println("程序猿哼哧哼哧干活中...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
TestJob
/**
* @ClassName TestJob
* @Desc 测试任务
* @Author xieqx
* @Date 2020/12/9 16:03
**/
public class TestJob implements Job {
@Override
public void execute() {
System.out.println("测试开始测试");
try {
Thread.sleep(10);
System.out.println("测试用例测试...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
2.4、测试场景
请求立马响应,但是异步任务在后面处理
来源:https://blog.csdn.net/liushangzaibeijing/article/details/111058826
猜你喜欢
- mkdir函数用于创建目录。格式如下:#include<sys/types.h>#include<sys/stat.h&g
- 1、找准入口,使用ClassPathXmlApplicationContext的构造方法加载配置文件,用于加载classPath下的配置文件
- 背景最近好几个项目在运行过程中客户都提出文件上传大小的限制能否设置的大一些,用户经常需要上传好几个G的资料文件,如图纸,视频等,并且需要在上
- 一、百度百科Sentinel 是面向分布式服务架构的高可用流量防护组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防
- 背景实际开发中,常常需要将比较复杂的 JSON 字符串转换为对应的 Java 对象。这里记录下解决方案。如下所示,是入侵事件检测得到的 JS
- SharedPreferences是Android中最容易理解的数据存储技术,实际上SharedPreferences处理的就是一个key-
- 本文实例为大家分享了C语言实现贪吃蛇游戏的具体代码,供大家参考,具体内容如下IDE用的是 VS2019先看效果 代码全览game.
- 前言之前用简书的时候一直是在web端,后来下载了客户端,看到了搜索的那个动画,就尝试的去写了,没写之前感觉挺容易的,写了之后,就感觉里面还是
- 一个发送验证码的需求:包括限制文本框输入长度和只允许输入数字按惯例 先上图:class MyBody extends StatefulWid
- 首先打开 Visual Studio Installer 可以看到vs2022 只支持安装4.6及以上的版本,如图所示。那么该如何安装4.6
- NDK部分1、下载ndk这里就一笔带过了。2、解压ndk不要解压,文件权限会出错。执行之,会自动解压,然后mv到想放的地方。我放到了”/us
- 序言小编在项目中有遇到使用 flutter 实现扫码枪接入的需求。为方便使用,小编把能力封装成 package 并发布。好记性不如烂笔头,下
- 废话开篇:iOS与android在实现列表界面的时候是有重用机制的,目的就是减少内存开销,用时间换空间。个人感觉flutter并没有特别强调
- 1.引言在开发中,拖放是一种比较常见的手势操作,使用它能够让应用的交互更加地便捷和友好,本文将简要介绍如何为Android中的View添加拖
- Spring JPA 增加字段执行异常用Spring jpa Entity里面增加了几个字段,但启动报错,提示column Unable t
- MediaQuery通常情况下,不会直接将MediaQuery当作一个控件,而是使用MediaQuery.of获取当前设备的信息,用法如下:
- 背景今天面试字节算法岗时被问到的问题,让我用C++实现一个softmax函数。softmax是逻辑回归在多分类问题上的推广。大概的公式如下:
- java.lang.ArrayStoreException 分析这个demo来说明怎样排查一个spring boot 1应用升级到sprin
- 很多时候我们开发的软件需要向用户提供软件参数设置功能,例如我们常用的QQ,用户可以设置是否允许陌生人添加自己为好友。对于软件配置参数的保存,
- 最近在研究android自定义控件属性,学到了TypedArray以及attrs。大家也可以结合《理解Android中的自定义属性》这篇文章