日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Servlet3异步原理

發(fā)布時間:2023/12/14 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Servlet3异步原理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、什么是異步Servlet

當一個新的請求到達時,Tomcat會從線程池里拿出一個線程來處理請求,這個線程會調(diào)用你的Web應用,Web應用在處理請求的過程中,Tomcat線程會一直阻塞,直到Web應用處理完畢才能再輸出響應,最后Tomcat才回收這個線程

假如你的Web應用需要較長的時間來處理請求(比如數(shù)據(jù)庫查詢或者等待下游的服務調(diào)用返回),那么Tomcat線程一直不回收,會占用系統(tǒng)資源,在極端情況下會導致線程饑餓,也就是說Tomcat沒有更多的線程來處理新的請求

那該如何解決這個問題呢?

Servlet3.0中引入的異步Servlet。主要是在Web應用里啟動一個單獨的線程來執(zhí)行這些比較耗時的請求,而Tomcat線程立即返回,不再等待Web應用將請求處理完,這樣Tomcat線程可以立即被回收到線程池,用來響應其他請求,降低了系統(tǒng)的資源消耗,同時還能提高系統(tǒng)的吞吐量

二、異步Servlet示例

SpringBoot啟動類添加@ServletComponentScan注解,掃描Servlet

@ServletComponentScan @SpringBootApplication public class AsyncServletApplication {public static void main(String[] args) {SpringApplication.run(AsyncServletApplication.class, args);}}

異步Servlet

@WebServlet(urlPatterns = {"/async"}, asyncSupported = true) public class AsyncServlet extends HttpServlet {//Web應用線程池,用來處理異步ServletExecutorService executor = Executors.newSingleThreadExecutor();@Overridepublic void service(HttpServletRequest req, HttpServletResponse resp) {//調(diào)用startAsync或者異步上下文AsyncContext asyncContext = req.startAsync();//添加AsyncListenerasyncContext.addListener(new AsyncServletListener());//用線程池來執(zhí)行耗時操作executor.execute(new Runnable() {@Overridepublic void run() {//在這里做耗時的操作try {asyncContext.getResponse().getWriter().println("Handling Async Servlet");} catch (IOException e) {}//異步Servlet處理完了調(diào)用異步上下文的complete方法asyncContext.complete();}});} }

異步Servlet監(jiān)聽

public class AsyncServletListener implements AsyncListener {private static final Logger LOGGER = LoggerFactory.getLogger(AsyncServletListener.class);/*** 異步線程執(zhí)行完畢時回調(diào)** @param asyncEvent* @throws IOException*/@Overridepublic void onComplete(AsyncEvent asyncEvent) throws IOException {LOGGER.info("AsyncServlet onComplete");}/*** 異步線程執(zhí)行超時回調(diào)** @param asyncEvent* @throws IOException*/@Overridepublic void onTimeout(AsyncEvent asyncEvent) throws IOException {LOGGER.info("AsyncServlet onTimeout");}/*** 異步線程執(zhí)行出錯回調(diào)** @param asyncEvent* @throws IOException*/@Overridepublic void onError(AsyncEvent asyncEvent) throws IOException {LOGGER.info("AsyncServlet onError");}/*** 異步線程開始執(zhí)行時回調(diào)** @param asyncEvent* @throws IOException*/@Overridepublic void onStartAsync(AsyncEvent asyncEvent) throws IOException {LOGGER.info("AsyncServlet onStartAsync");} }

上面的代碼有三個要點:

  • 通過注解的方式來注冊Servlet,除了@WebServlet注解,還需要加上asyncSupported=true的屬性,表明當前的Servlet是一個異步Servlet

  • Web應用程序需要調(diào)用Request對象的startAsync()方法來拿到一個異步上下文AsyncContext。這個上下文保存了請求和響應對象

  • Web應用需要開啟一個新線程來處理耗時的操作,處理完成后需要調(diào)用AsyncContext的complete()方法。目的是告訴Tomcat,請求已經(jīng)處理完成

雖然異步Servlet允許用更長的時間來處理請求,但是也有超時限制的,默認是30秒,如果30秒內(nèi)請求還沒處理完,Tomcat會觸發(fā)超時機制,向瀏覽器返回超時錯誤,如果這個時候你的Web應用再調(diào)用asyncContext.complete()方法,會得到一個IllegalStateException異常

三、異步Servlet原理

接收到Request請求之后,由Tomcat工作線程從HttpServletRequest中獲得一個異步上下文AsyncContext對象,然后由Tomcat工作線程把AsyncContext對象傳遞給業(yè)務處理線程,同時Tomcat工作線程歸還到工作線程池,這一步就是異步開始。在業(yè)務處理線程中完成業(yè)務邏輯的處理,生成response返回給客戶端

在Servlet3.0中雖然處理請求可以實現(xiàn)異步,但是InputStream和OutputStream的IO操作還是阻塞的,當數(shù)據(jù)量大的Request Body或者Response Body的時候,就會導致不必要的等待。從Servlet3.1以后增加了非阻塞IO,需要Tomcat8.x支持,通過在HttpServletRequest和HttpServletResponse中分別添加ReadListener和WriterListener方式,只有在IO數(shù)據(jù)滿足一定條件時(比如數(shù)據(jù)準備好時),才進行后續(xù)的操作

@WebServlet(urlPatterns = {"/async"}, asyncSupported = true) public class AsyncServlet extends HttpServlet {//Web應用線程池,用來處理異步ServletExecutorService executor = Executors.newSingleThreadExecutor();@Overridepublic void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {//調(diào)用startAsync或者異步上下文AsyncContext asyncContext = req.startAsync();//添加AsyncListenerasyncContext.addListener(new AsyncServletListener());ServletInputStream inputStream = req.getInputStream();inputStream.setReadListener(new ReadListener() {@Overridepublic void onDataAvailable() throws IOException {}@Overridepublic void onAllDataRead() throws IOException {//用線程池來執(zhí)行耗時操作executor.execute(new Runnable() {@Overridepublic void run() {//在這里做耗時的操作try {asyncContext.getResponse().getWriter().println("Handling Async Servlet");} catch (IOException e) {}//異步Servlet處理完了調(diào)用異步上下文的complete方法asyncContext.complete();}});}@Overridepublic void onError(Throwable throwable) {}});} }

參考:

https://time.geekbang.org/column/article/106935

https://blog.csdn.net/wangxindong11/article/details/78591396

https://www.cnblogs.com/davenkin/p/async-servlet.html

總結

以上是生活随笔為你收集整理的Servlet3异步原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。