异步Servlet

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

 1.需要解决的问题

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

 2.同步Servlet

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

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

/**
 * 同步Servlet 样例
 * @author johnny
 */
@WebServlet(name = "Sync-SyncServlet", urlPatterns = "/sync")
@Slf4j
public class SyncServlet extends HttpServlet {

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    log.info("doPost sync servlet");
}

@Override
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 发布!

Aska小强
100 声望6 粉丝