Servlet 3.0 Async-Supported 异步支持

传统Servlet处理请求的方式

  1. 接收请求,开一个线程用于处理它。
  2. 对请求中携带的部分数据进行预处理。
  3. 调用业务方法,完成业务功能。
  4. 将结果(响应)返回,完成使命,善后处理,结束线程。

传统Serlvet处理请求的问题

一般来说,某个Servlet线程一旦开启,就要到其完成所有功能后才能结束(传统常识)。
在Servlet处理请求的流程中,往往最耗时的环节是调用业务方法、完成业务功能,(因为一般在此时会进行数据库读写,网络调用等),会使Servlet线程在此阻塞一段时间,因此会损失一些性能。在功能比较简单且负载压力比较小的话,这种问题不太容易被察觉出来,但是在负载比较重的情况下,由于并发数比较多,容器会开启大量线程,如果还是采用传统的处理方式,容器线程池往往会被耗干,从而无法来接受新的请求。

解决思路

要创建可伸缩的web应用程序,必须确保没有与请求关联的线程处于闲置状态,因此容器可以使用它们来处理新请求。(高效利用资源)

解决方案

Servlet 3.0 针对这个问题做了开创性的工作,现在通过使用 Servlet 3.0 的异步处理支持。(之前版本不支持)
Java EE为servlet和过滤器提供异步处理支持。如果servlet或过滤器在处理请求时达到了潜在的阻塞操作,它可以将操作分配给异步执行上下文,并将与请求关联的线程立即返回到容器中,而不会生成响应。阻塞操作在不同线程中完成异步执行上下文,可以生成响应或将请求发送给另一个servlet。

正确的打开方式

配置

  1. web.xml
  <async-supported>true</async-supported>
  1. Servlet
@WebServlet(asyncSupported = true, urlPatterns = { "/Demo" })

Filter的设置相似

使用

下面以Servlet的方式进行举例,Filter的方式大同小异,不再赘述。

@WebServlet(asyncSupported = true, urlPatterns = { "/Demo" })
public class DemoServlet extends HttpServlet {
 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  final AsyncContext ac = request.startAsync();
  ac.start(() ->{
    try {
     Thread.sleep(2000);
     ac.getResponse().getWriter().append(new Date().toString());
    } catch (InterruptedException e) {
     e.printStackTrace();
    } catch (IOException e) {
     e.printStackTrace();
    }
    ac.complete();
   } );
 }
}

上面的代码(缩略过的)使用AsyncContext进行异步响应,请求该页面两秒后显示时间。
注意下面的几点:
1.AsyncContext ac = request.startAsync();
要在Request对象上通过StartAsync方法创建一个AsyncContext对象供在异步上下文中使用。

  1. ac.start( Runnable run ) 开启
    开启一个子线程中并在其中执行业务,并由其负责输出响应,主线程退出。
  2. ac.getResponse() / ac.getRequest()
    用于在异步上下文中获取Req&Res对象。
  3. ac.complete(); / dispatch(String path)
    complete(),用于完成异步操作并关闭与此异步上下文关联的响应。在异步上下文中写入响应对象之后,调用此方法。
    dispatch(String path) 用起来感觉等同于ServletRequest.getRequestDispatcher(String)。

参考资料

2,919 total views, 14 views today

发表评论

电子邮件地址不会被公开。 必填项已用*标注