高性能的关键异步请求的原生态

本文作者:黄少存,叩丁狼高级讲师。原创文章,转载请注明出处。

前言:说到异步请求咱们得先知道何为同步请求,从而对比来理解异步请求.同步请求简述, 浏览器发送请求->web服务器开启线程处理请求->处理完把结果返回给浏览器. 咱们来看下程序中同步请求的业务逻辑图.

同步请求

高性能的关键异步请求的原生态_第1张图片

对于同步操作来说,web服务器开启请求处理线程之后需要等待业务的处理完成才能做响应.对于同步请求来说这是理所当然的事情. 一般这样的操作也足够.但是如果有特殊要求,比如高并发,处理业务时间长的操作比较多,那会出现什么问题呢?

由于请求处理线程的总数是有限的,以上特殊请求会出现请求线程不够用的请求,因为可能都处于阻塞状态,影响服务器的吞吐量.所以就得使用异步请求,这也是高性能的关键.

异步请求

高性能的关键异步请求的原生态_第2张图片

对于异步请求操作来说,web 服务器的请求处理线程在处理请求上大大减少了时间,仅仅是接收了请求之后唤醒了新的业务处理线程,然后就结束了.这样的话,请求处理线程就可以留出多余的时间去处理其他的请求.提高了服务器的吞吐量.

既然异步请求可以提高处理能力,那如何实现异步请求呢?

其实 jetty 服务器就实现了异步请求,只是那是比较早期的操作了,现在有些框架也是有异步模块的,比如 spring mvc,但在 JavaWeb 中,其最根本的还是 Servlet3.0 的异步请求规范.接下来咱们就来看下servlet 原生态的异步请求实现.

servlet 原生态异步请求

步骤:

  1. 开启异步请求支持
  2. 异步请求代码书写

开启异步请求支持

开启异步请求支持有两种方式.

  1. 通过注解 asyncSupported=true 来实现
  2. 通过 web.xml 配置true来实现
  3. 异步请求监听

异步请求代码书写

// 配置资源路径和开启异步请求支持
@WebServlet(urlPatterns = {"/async"}, asyncSupported = true)
public class AsyncServlet extends HttpServlet {
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");

        //获取异步请求上下文对象
        AsyncContext async = req.startAsync();
        // 设置异步处理超时时间,默认30秒
        async.setTimeout(40 * 1000);

        // 启动异步处理,关键操作
        async.start(() -> {
            try {
                // 模拟业务处理耗时
                Thread.sleep(10 * 1000);
                req.setAttribute("msg", "异步处理后的数据" + new Date().toLocaleString());
                // 将请求转发到 index.jsp 页面
                async.dispatch("/async.jsp");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        // 直接显示到页面的数据,不需等待以上业务处理
        System.out.println("请求处理线程释放:" + new Date().toLocaleString());
    }
}

async.jsp 页面书写

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    异步请求


    发起请求
异步请求数据: ${msg}

最终看到的结果
高性能的关键异步请求的原生态_第3张图片

异步请求监听器接口AsyncListener

Servlet 3.0 为异步处理提供了一个监听器,使用 AsyncListener 接口表示。此接口负责管理异步事件,它可以监控如下四种事件:

  1. 异步线程开始时,调用AsyncListener的onStartAsync(AsyncEvent event)方法;
  2. 异步线程出错时,调用AsyncListener的onError(AsyncEvent event)方法;
  3. 异步线程执行超时,则调用AsyncListener的onTimeout(AsyncEvent event)方法;
  4. 异步执行完毕时,调用AsyncListener的onComplete(AsyncEvent event)方法;
// 配置资源路径和开启异步请求支持
@WebServlet(urlPatterns = {"/async"}, asyncSupported = true)
public class AsyncServlet extends HttpServlet {
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        //获取异步请求上下文对象
        AsyncContext async = req.startAsync();
        async.addListener(new MyAsyncListener());

        //...
}
public class MyAsyncListener implements AsyncListener {
    public void onComplete(AsyncEvent event) throws IOException {
        System.out.println("完成后清理操作等..");
    }
    public void onTimeout(AsyncEvent event) throws IOException {
        System.out.println("超时处理..");
    }
    public void onError(AsyncEvent event) throws IOException {
    }
    public void onStartAsync(AsyncEvent event) throws IOException {
    }
}

高性能的关键异步请求的原生态_第4张图片

你可能感兴趣的:(Java基础,Java)