前言
通過(guò)我之前的Tomcat系列文章,相信看我博客的同學(xué)對(duì)Tomcat應(yīng)該有一個(gè)比較清晰的了解了,在前幾篇博客我們討論了Tomcat在SpringBoot框架中是如何啟動(dòng)的,討論了Tomcat的內(nèi)部組件是如何設(shè)計(jì)以及請(qǐng)求是如何流轉(zhuǎn)的,那么我們這邊博客聊聊Tomcat的異步Servlet,Tomcat是如何實(shí)現(xiàn)異步Servlet的以及異步Servlet的使用場(chǎng)景。
手?jǐn)]一個(gè)異步的Servlet
我們直接借助SpringBoot框架來(lái)實(shí)現(xiàn)一個(gè)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 { //開(kāi)啟異步,獲取異步上下文 final AsyncContext ctx = req.startAsync(); // 提交線程池異步執(zhí)行 executorService.execute(new Runnable() { @Override public void run() { try { log.info("async Service 準(zhǔn)備執(zhí)行了"); //模擬耗時(shí)任務(wù) Thread.sleep(10000L); ctx.getResponse().getWriter().print("async servlet"); log.info("async Service 執(zhí)行了"); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } //最后執(zhí)行完成后完成回調(diào)。 ctx.complete(); } }); }
上面的代碼實(shí)現(xiàn)了一個(gè)異步的Servlet,實(shí)現(xiàn)了 doGet
方法注意在SpringBoot中使用需要再啟動(dòng)類加上 @ServletComponentScan
注解來(lái)掃描Servlet。既然代碼寫好了,我們來(lái)看看實(shí)際運(yùn)行效果。
我們發(fā)送一個(gè)請(qǐng)求后,看到頁(yè)面有響應(yīng),同時(shí),看到請(qǐng)求時(shí)間花費(fèi)了10.05s,那么我們這個(gè)Servlet算是能正常運(yùn)行啦。有同學(xué)肯定會(huì)問(wèn),這不是異步servlet嗎?你的響應(yīng)時(shí)間并沒(méi)有加快,有什么用呢?對(duì),我們的響應(yīng)時(shí)間并不能加快,還是會(huì)取決于我們的業(yè)務(wù)邏輯,但是我們的異步servlet請(qǐng)求后,依賴于業(yè)務(wù)的異步執(zhí)行,我們可以立即返回,也就是說(shuō),Tomcat的線程可以立即回收,默認(rèn)情況下,Tomcat的核心線程是10,最大線程數(shù)是200,我們能及時(shí)回收線程,也就意味著我們能處理更多的請(qǐng)求,能夠增加我們的吞吐量,這也是異步Servlet的主要作用。
異步Servlet的內(nèi)部原理
了解完異步Servlet的作用后,我們來(lái)看看,Tomcat是如何是先異步Servlet的。其實(shí)上面的代碼,主要核心邏輯就兩部分, final AsyncContext ctx = req.startAsync();
和 ctx.complete();
那我們來(lái)看看他們究竟做了什么?
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; }
新聞熱點(diǎn)
疑難解答
圖片精選