首页 > 网站 > Tomcat > 正文

详解Tomcat是如何实现异步Servlet的

2024-09-06 19:00:54
字体:
来源:转载
供稿:网友

前言

通过我之前的Tomcat系列文章,相信看我博客的同学对Tomcat应该有一个比较清晰的了解了,在前几篇博客我们讨论了Tomcat在SpringBoot框架中是如何启动的,讨论了Tomcat的内部组件是如何设计以及请求是如何流转的,那么我们这边博客聊聊Tomcat的异步Servlet,Tomcat是如何实现异步Servlet的以及异步Servlet的使用场景。

手撸一个异步的Servlet

我们直接借助SpringBoot框架来实现一个Servlet,这里只展示Servlet代码:

@WebServlet(urlPatterns = "/async",asyncSupported = true)@Slf4jpublic class AsyncServlet extends HttpServlet { ExecutorService executorService =Executors.newSingleThreadExecutor(); @Override  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  //开启异步,获取异步上下文  final AsyncContext ctx = req.startAsync();  // 提交线程池异步执行  executorService.execute(new Runnable() {   @Override   public void run() {    try {     log.info("async Service 准备执行了");     //模拟耗时任务     Thread.sleep(10000L);     ctx.getResponse().getWriter().print("async servlet");     log.info("async Service 执行了");    } catch (IOException e) {     e.printStackTrace();    } catch (InterruptedException e) {     e.printStackTrace();    }    //最后执行完成后完成回调。    ctx.complete();   }  }); }

上面的代码实现了一个异步的Servlet,实现了 doGet 方法注意在SpringBoot中使用需要再启动类加上 @ServletComponentScan 注解来扫描Servlet。既然代码写好了,我们来看看实际运行效果。

我们发送一个请求后,看到页面有响应,同时,看到请求时间花费了10.05s,那么我们这个Servlet算是能正常运行啦。有同学肯定会问,这不是异步servlet吗?你的响应时间并没有加快,有什么用呢?对,我们的响应时间并不能加快,还是会取决于我们的业务逻辑,但是我们的异步servlet请求后,依赖于业务的异步执行,我们可以立即返回,也就是说,Tomcat的线程可以立即回收,默认情况下,Tomcat的核心线程是10,最大线程数是200,我们能及时回收线程,也就意味着我们能处理更多的请求,能够增加我们的吞吐量,这也是异步Servlet的主要作用。

异步Servlet的内部原理

了解完异步Servlet的作用后,我们来看看,Tomcat是如何是先异步Servlet的。其实上面的代码,主要核心逻辑就两部分, final AsyncContext ctx = req.startAsync();ctx.complete(); 那我们来看看他们究竟做了什么?

 public AsyncContext startAsync(ServletRequest request,   ServletResponse response) {  if (!isAsyncSupported()) {   IllegalStateException ise =     new IllegalStateException(sm.getString("request.asyncNotSupported"));   log.warn(sm.getString("coyoteRequest.noAsync",     StringUtils.join(getNonAsyncClassNames())), ise);   throw ise;  }  if (asyncContext == null) {   asyncContext = new AsyncContextImpl(this);  }  asyncContext.setStarted(getContext(), request, response,    request==getRequest() && response==getResponse().getResponse());  asyncContext.setTimeout(getConnector().getAsyncTimeout());  return asyncContext; }
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表