Servlet3 异步原理与实践
一、什么是Servlet
Servlet 是基于 Java 的 Web 组件,由容器进行管理,来生成动态内容。像其他基于 Java 的组件技术一样,Servlet 也是基于平台无关的 Java 类格式,被编译为平台无关的字节码,可以被基于 Java 技术的 Web 服务器动态加载并运行。容器(Container),有时候也叫做 Servlet 引擎,是 Web 服务器为支持 Servlet 功能扩展的部分。客户端通过 Servlet 容器实现的 request/response paradigm(请求/应答模式) 与 Servlet 进行交互。
二、什么是Servlet规范
每当一个 Servlet 版本发布都会对应一个 Servlet 版本的规范,比如 Servlet2.5、Servlet3.0、Servlet3.1。
规范中描述了 Java Servlet API 的标准,定义了 Java Servlet API 中类、接口、方法签名的完整规范且附带的 Javadoc 文档供开发人员查阅,目的主要是为 Java Servlet 给出一个完整和清晰的解释。从下图可以看出 Servlet 规范版本和 Tomcat 支持的版本的对应关系。比如 Servlet3 是从 Tomcat7 以后开始支持的。

三、同步,异步,阻塞,非阻塞
同步异步是数据通信的方式,阻塞和非阻塞是一种状态。比如同步这种数据通讯方式里面可以有阻塞状态也可以有非阻塞状态。从另外一个角度理解同步和异步,就是如果一个线程干完的事情都是同步,有线程切换才能干完的事情就是异步。
四、Servlet3 的异步位置
这里说的位置是指,从 Tomcat 处理整个 request 请求流程中,异步处于哪一步。我们先梳理出在 NIO 模式下(是否使用 NIO 跟异步没有直接关系,这里是拿 NIO 模式下的 Tomcat 流程做说明),下面这个图是 Tomcat 的总体结构,里面用箭头标明了请求线路。

我们知道在 Tomcat 的组件中 Connector 和 Engine 是最核心的两个组件,Servlet3 的异步处理就是发生在 Connector 中。Tomcat 的组件之间的协作关系,后续会单独写一篇文章介绍。这里先有一个直观的认识。便与后续对异步理解。
五、Servlet3 的异步流程

接收到 request 请求之后,由 Tomcat 工作线程从 HttpServletRequest 中获得一个异步上下文 AsyncContext 对象,然后由 Tomcat 工作线程把 AsyncContext 对象传递给业务处理线程,同时 Tomcat 工作线程归还到工作线程池,这一步就是异步开始。在业务处理线程中完成业务逻辑的处理,生成 response 返回给客户端。在 Servlet3.0 中虽然处理请求可以实现异步,但是 InputStream 和 OutputStream 的 IO 操作还是阻塞的,当数据量大的 request body 或者 response body 的时候,就会导致不必要的等待。从 Servlet3.1 以后增加了非阻塞 IO,需要 Tomcat8.x 支持。
六、Servlet3 的异步使用步骤
我们使用的大致步骤如下:
1、声明 Servlet,增加 asyncSupported 属性,开启异步支持。
@WebServlet(urlPatterns = "/AsyncLongRunningServlet", asyncSupported = true)
2、通过 request 获取异步上下文 AsyncContext。
AsyncContext asyncCtx = request.startAsync();
3、开启业务逻辑处理线程,并将 AsyncContext 传递给业务线程。
executor.execute(new AsyncRequestProcessor(asyncCtx, secs));
4、在异步业务逻辑处理线程中,通过 asyncContext 获取 request 和 response,处理对应的业务。
5、业务逻辑处理线程处理完成逻辑之后,调用 AsyncContext 的 complete 方法。
asyncContext.complete();
从而结束该次异步线程处理。
七、Servlet3 的异步使用示例
7.1、AsyncLongRunningServlet.java 处理 Servlet 请求,并开启异步
package com.test.servlet3;
This chapter requires login to view full content. You are viewing a preview.
Login to View Full Content