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();
   }
}

  开启异步支持(默认异步支持不开启)有两种方式:

使用注解

servlet异步请求的实现

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、测试场景

请求立马响应,但是异步任务在后面处理

servlet异步请求的实现

servlet异步请求的实现

来源:https://blog.csdn.net/liushangzaibeijing/article/details/111058826

标签:servlet,异步请求
0
投稿

猜你喜欢

  • 带你入门Java的泛型

    2023-06-08 02:48:24
  • Android Studio 3.0中mipmap-anydpi-v26是什么东东

    2023-10-11 01:17:44
  • C#操作ini文件的帮助类

    2022-12-26 17:11:09
  • Android线程管理之ActivityThread

    2022-05-08 07:48:35
  • Java 远程调用失败重试的操作方法

    2021-08-26 21:42:58
  • Mybatis打印替换占位符后的完整Sql教程

    2023-11-08 22:56:13
  • Mybatis自动创建表和更新表结构

    2022-11-17 19:43:00
  • Spring Bean生命周期之BeanDefinition的合并过程详解

    2023-11-29 02:50:35
  • C#类的访问修饰符用法分析

    2021-12-22 22:23:01
  • java基础javeSE程序逻辑控制语法

    2022-09-21 23:41:47
  • Android studio实现简易计算器App功能

    2023-03-07 07:57:57
  • Flutter倒计时/计时器的实现代码

    2023-07-01 03:50:50
  • Java Springboot的目的你知道吗

    2022-12-20 14:16:24
  • Mybatis拦 截 器实现数据权限的示例代码

    2023-11-19 20:15:04
  • c# 通过经纬度查询 具体的地址和区域名称

    2023-08-15 11:41:53
  • java使用poi生成excel的步骤

    2021-08-25 07:03:45
  • Java获取视频时长、大小的示例

    2023-01-16 01:48:44
  • SpringBoot使用validation-api实现参数校验的示例

    2022-12-02 14:33:40
  • SpringBoot使用WebSocket的方法实例详解

    2022-12-26 03:19:25
  • Java如何执行cmd命令

    2022-05-02 09:54:45
  • asp之家 软件编程 m.aspxhome.com