异步Servlet 特性

 1.需要解决的问题

  • 1.为什么使用异步Servlet? 同步Servlet阻塞了什么
  • 2.异步Servlet编写流程

 2.同步Servlet

 同步Servlet是指 tomcat线程去执行 servlet方法后,会一直被阻塞,直到业务代码执行完毕 ,这样tomcat 吞吐量就有限

 直接看代码,应该都很熟悉 同步Servlet的开发吧,

/**
* 同步Servlet 样例
* [@author](https://my.oschina.net/arthor) johnny
*/
@WebServlet(name = "Sync-SyncServlet", urlPatterns = "/sync")
[@Slf4j](https://my.oschina.net/slf4j)
public class SyncServlet extends HttpServlet {

[@Override](https://my.oschina.net/u/1162528)
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    log.info("doPost sync servlet");
}

[@Override](https://my.oschina.net/u/1162528)
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    long start = System.currentTimeMillis();

    try {
        //模拟业务代码处理
        TimeUnit.SECONDS.sleep(3);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    long end = System.currentTimeMillis();
    log.info("doGet sync servlet 耗时: {} 秒", (end - start) / 1000);

  }
}

Xnip20200225_161959.png

 3.异步Servlet

 异步Servlet主要是要注意

  • 1.开启异步Servlet asyncSupported = true

  • 2.获取异步上下文 AsyncContext asyncContext = request.startAsync();

  • 3.将业务耗时方法放入 线程池中去异步执行 注意需要传入异步上下文,供业务方法内部调用,如

      CompletableFuture.runAsync(() -> {
          doSomeThing(asyncContext, asyncContext.getRequest(), asyncContext.getResponse());
      });
    
  • 4.业务方法调用上下文结束 asyncContext.complete();

      /**
      * 异步Servlet 案例
      *
      * @author johnny
      * <p>
      * asyncSupported = true 表示开启异步支持
      */
      @WebServlet(name = "AsyncServlet",
      	asyncSupported = true,
      	urlPatterns = "/async")
      @Slf4j
      public class AsyncServlet extends HttpServlet {
      @Override
      protected void doPost(HttpServletRequest request, HttpServletResponse response) throws 	ServletException, IOException {
      log.info("【doPost async Servlet 】");
      }
    
      @Override
      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      long start = System.currentTimeMillis();
    
      //获取异步上下文
      AsyncContext asyncContext = request.startAsync();
    
      //使用java8的 CompletableFuture,将任务放到线程池中去执行
      CompletableFuture.runAsync(() -> {
          doSomeThing(asyncContext, asyncContext.getRequest(), asyncContext.getResponse());
      });
    
      long end = System.currentTimeMillis();
    
      log.info("【doGet async Servlet 耗时 {} 】", (end - start));
      }
    
      private void doSomeThing(AsyncContext asyncContext, ServletRequest request, ServletResponse response) {
    
      //执行业务代码
      try {
          TimeUnit.SECONDS.sleep(3);
      } catch (InterruptedException e) {
          e.printStackTrace();
      }
      //告诉异步上下文 结束了
    
      asyncContext.complete();
    
       }
      }
    

 浏览器访问

http://localhost:8080/async

 可以看到日志,该Servlet仅仅只耗时 7毫秒,这样tomcat 调用这个Servlet得线程 又可以去处理其他请求,从而增加了吞吐量,  这就是异步Servlet的作用

Xnip20200225_171737.png

 4.解答问题:为什么使用异步Servlet? 同步Servlet阻塞了什么

 拿Tomcat服务器为例,当请求到达时候,Tomcat服务器会为每个请求创建一个线程,然后调用对应的Servlet的doGet或doPost方法,如果在该Servlet 的doPost 或者 doGet 方法中有业务耗时操作,则该线程会一直等待,直到业务逻辑处理完成才会把对应的 线程收回到Tomcat 重新接收请求

而异步Servelt的目的就是 不用Tomcat的线程去等待,直接将其返回去接收其他请求,使用异步Servlet的支持 可以把耗时操作放入线程池中当执行完毕后 通知异步上下文去返回结果给前端 ,所以前端的反应其实看不出来什么效果,但是后台会有很大差异

 5.疑问

  5.1 使用SpringMVC 怎么使用异步

  看到这里肯定有人会问,现在谁还会去用Servlet去编程,都是用SpringMvc去编程了,当然SpringMvc早在3.2的版本中就已经对异步Servlet进行了支持,到现在已经提供了3中方式去实现异步

  • DeferredResult
  • Callable
  • CompletionStage/CompletableFuture

  详细使用教程后期会再写一篇,关于SpringMVC对异步Servlet的支持!

  5.2 有了SpringMVC 的异步支持 为什么还需要 Spring5提供的 WebFlux

  其实SpringMvc支持的异步已经能够满足我们的基本开发需要,那么为什么Spring还要引入 WebFlux 技术栈, 就是 一种趋势,并发编程模型已经成趋势

 6.总结

本篇主要讲解 如何使用 异步Servlet的处理请求,并且演示 同步Servlet和异步Servlet的区别,以及异步Servlet带来哪些好处。

涉及的同步Servlet会带来的问题,并且简单聊了下SpringMVC里对异步Servlet的支持,等等。。 后续会编写一篇关于SpringMVC对异步Servlet支持的详细教程,其实底层就是异步Servlet的使用 加油!!

个人博客系统:https://www.askajohnny.com 欢迎访问! 本文由博客一文多发平台 OpenWrite 发布!