成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Servlet3中異步Servlet特性介紹

譯文
開發 前端
在Jave EE 6規范中,關于Servlet 3規范的相關功能增強,一直是讓大部分用戶忽略的,連直到最新的Spring MVC 3.2才支持Servlet 3的異步調用。這可能跟大部分用戶使用的JAVE EE容器依然是舊的有關系(如支持Servlet 3規范的需要Tomcat 7,但目前不少用戶還在使用Tomcat 6)。在本文中,將以實際的例子來講解下Servlet 3規范中對異步操作的支持。

在Jave EE 6規范中,關于Servlet 3規范的相關功能增強,一直是讓大部分用戶忽略的,連直到最新的Spring MVC 3.2才支持Servlet 3的異步調用。這可能跟大部分用戶使用的JAVE EE容器依然是舊的有關系(如支持Servlet 3規范的需要Tomcat 7,但目前不少用戶還在使用Tomcat 6)。

在本文中,將以實際的例子來講解下Servlet 3規范中對異步操作的支持。

首先要簡單了解,在Servlet 3中,已經支持使用注解的方式去進行Servlet的配置,這樣就不需要在web.xml中進行傳統的xml的配置了,最常用的注解是使用@WebServlet、@WebFilter、@WebInitParam,它們分別等價于傳統xml配置中的<Servlet>、<WebFilter>、<InitParam>,其他參數可參考Servlet 3中的規范說明。

下面我們開始了解下,如果不使用異步特性的一個例子,代碼如下:

  1. @WebServlet("/LongRunningServlet")  
  2. public class LongRunningServlet extends HttpServlet {  
  3.     private static final long serialVersionUID = 1L;  
  4.   
  5.     protected void doGet(HttpServletRequest request,  
  6.             HttpServletResponse response) throws ServletException, IOException {  
  7.         long startTime = System.currentTimeMillis();  
  8.         System.out.println("LongRunningServlet Start::Name="  
  9.                 + Thread.currentThread().getName() + "::ID="  
  10.                 + Thread.currentThread().getId());  
  11.   
  12.         String time = request.getParameter("time");  
  13.         int secs = Integer.valueOf(time);  
  14.         //如果超過10秒,默認用10秒  
  15.         if (secs > 10000)  
  16.             secs = 10000;  
  17.   
  18.         longProcessing(secs);  
  19.   
  20.         PrintWriter out = response.getWriter();  
  21.         long endTime = System.currentTimeMillis();  
  22.         out.write("Processing done for " + secs + " milliseconds!!");  
  23.         System.out.println("LongRunningServlet Start::Name="  
  24.                 + Thread.currentThread().getName() + "::ID="  
  25.                 + Thread.currentThread().getId() + "::Time Taken="  
  26.                 + (endTime - startTime) + " ms.");  
  27.     }  
  28.   
  29.     private void longProcessing(int secs) {  
  30.               //故意讓線程睡眠       
  31.         try {  
  32.             Thread.sleep(secs);  
  33.         } catch (InterruptedException e) {  
  34.             e.printStackTrace();  
  35.         }  
  36.     }  
  37.   

 運行上面的例子,輸入

http://localhost:8080/AsyncServletExample/LongRunningServlet?time=8000,則可以看到輸出為:

LongRunningServlet Start::Name=http-bio-8080-exec-34::ID=103

1. LongRunningServlet Start::Name=http-bio-8080-exec-34::ID=103::Time Taken=8002 ms.

  可以觀察到,在主線程啟動后,servlet線程為了處理longProcessing的請求,足足等待了8秒,最后才輸出結果進行響應,這樣對于高并發的應用來說這是很大的瓶頸,因為必須要同步等到待處理的方法完成后,Servlet容器中的線程才能繼續接收其他請求,在此之前,Servlet線程一直處于阻塞狀態。

  在Servlet 3.0規范前,是有一些相關的解決方案的,比如常見的就是使用一個單獨的工作線程(worker thread)去處理這些耗費時間的工作,而Servlet 容器中的線程在把工作交給工作線程處理后則馬上回收到Servlet容器中去。比如Tomcat的Comet、WebLogic的的FutureResponseServlet和WebSphere的Asynchronous Request Dispatcher都是這類型的解決方案。

   但只這些方案的弊端是沒辦法很容易地在不修改代碼的情況下遷移到其他Servlet容器中,這就是Servlet 3中要定義異步Servlet的原因所在。

  下面我們通過例子來說明異步Servlet的實現方法:

1、 首先設置servlet要支持異步屬性,這個只需要設置asyncSupported屬性為true就可以了。

2、 因為實際上的工作是委托給另外的線程的,我們應該實現一個線程池,這個可以通過使用Executors框架去實現(具體參考http://www.journaldev.com/1069/java-thread-pool-example-using-executors-and-threadpoolexecutor一文),并且使用Servlet Context listener去初始化線程池。

3、 我們需要通過ServletRequest.startAsync()方法獲得AsyncContext的實例。AsyncContext提供了方法去獲得ServletRequest和ServletResponse的對象引用。它也能使用dispatch()方法去將請求forward到其他資源。

4、 我們將實現Runnable接口,并且在其實現方法中處理各種耗時的任務,然后使用AsyncContext對象去將請求dispatch到其他資源中去或者使用ServletResponse對象輸出。一旦處理完畢,將調用AsyncContext.complete()方法去讓容器知道異步處理已經結束。

5、 我們還可以在AsyncContext對象增加AsyncListener的實現類以實現相關的徽調方法,可以使用這個去提供將錯誤信息返回給用戶(如超時或其他出錯信息),也可以做一些資源清理的工作。

  我們來看下完成后例子的工程結構圖如下:

 

 

#p#

下面我們看下實現了ServletContextListener類的監聽類代碼:

  1.   AppContextListener.java 
  2. package com.journaldev.servlet.async; 
  3.  
  4. import java.util.concurrent.ArrayBlockingQueue; 
  5. import java.util.concurrent.ThreadPoolExecutor; 
  6. import java.util.concurrent.TimeUnit; 
  7.  
  8. import javax.servlet.ServletContextEvent; 
  9. import javax.servlet.ServletContextListener; 
  10. import javax.servlet.annotation.WebListener; 
  11.  
  12. @WebListener 
  13. public class AppContextListener implements ServletContextListener { 
  14.  
  15. public void contextInitialized(ServletContextEvent servletContextEvent) { 
  16.  
  17. // 創建線程池 
  18. ThreadPoolExecutor executor = new ThreadPoolExecutor(100, 200, 50000L, 
  19. TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(100)); 
  20. servletContextEvent.getServletContext().setAttribute("executor", 
  21. executor); 
  22.  
  23.  
  24. public void contextDestroyed(ServletContextEvent servletContextEvent) { 
  25. ThreadPoolExecutor executor = (ThreadPoolExecutor) servletContextEvent 
  26. .getServletContext().getAttribute("executor"); 
  27. executor.shutdown(); 
  28.  

然后是worker線程的實現代碼,如下:

  1. AsyncRequestProcessor.java 
  2. package com.journaldev.servlet.async; 
  3.  
  4. import java.io.IOException; 
  5. import java.io.PrintWriter; 
  6.  
  7. import javax.servlet.AsyncContext; 
  8.  
  9. public class AsyncRequestProcessor implements Runnable { 
  10.  
  11.     private AsyncContext asyncContext; 
  12.     private int secs; 
  13.  
  14.     public AsyncRequestProcessor() { 
  15.     } 
  16.  
  17.     public AsyncRequestProcessor(AsyncContext asyncCtx, int secs) { 
  18.         this.asyncContext = asyncCtx
  19.         this.secs = secs; 
  20.     } 
  21.  
  22.     @Override 
  23.     public void run() { 
  24.         System.out.println("Async Supported? " 
  25.                 + asyncContext.getRequest().isAsyncSupported()); 
  26.         longProcessing(secs); 
  27.         try { 
  28.             PrintWriter out = asyncContext.getResponse().getWriter(); 
  29.             out.write("Processing done for " + secs + " milliseconds!!"); 
  30.         } catch (IOException e) { 
  31.             e.printStackTrace(); 
  32.         } 
  33.         //完成異步線程處理 
  34.         asyncContext.complete(); 
  35.     } 
  36.  
  37.     private void longProcessing(int secs) { 
  38.         // 休眠指定的時間 
  39.         try { 
  40.             Thread.sleep(secs); 
  41.         } catch (InterruptedException e) { 
  42.             e.printStackTrace(); 
  43.         } 
  44.     } 

請在這里注意AsyncContext的使用方法,以及當完成異步調用時必須調用asyncContext.complete()方法。

現在看下AsyncListener類的實現

  1. package com.journaldev.servlet.async; 
  2.  
  3. import java.io.IOException; 
  4. import java.io.PrintWriter; 
  5.  
  6. import javax.servlet.AsyncEvent; 
  7. import javax.servlet.AsyncListener; 
  8. import javax.servlet.ServletResponse; 
  9. import javax.servlet.annotation.WebListener; 
  10.  
  11. @WebListener 
  12. public class AppAsyncListener implements AsyncListener { 
  13.  
  14.     @Override 
  15.     public void onComplete(AsyncEvent asyncEvent) throws IOException { 
  16.         System.out.println("AppAsyncListener onComplete"); 
  17.         // 在這里可以做一些資源清理工作 
  18.     } 
  19.  
  20.     @Override 
  21.     public void onError(AsyncEvent asyncEvent) throws IOException { 
  22.         System.out.println("AppAsyncListener onError"); 
  23.         //這里可以拋出錯誤信息 
  24.     } 
  25.  
  26.     @Override 
  27.     public void onStartAsync(AsyncEvent asyncEvent) throws IOException { 
  28.         System.out.println("AppAsyncListener onStartAsync"); 
  29.         //可以記錄相關日志 
  30.     } 
  31.  
  32.     @Override 
  33.     public void onTimeout(AsyncEvent asyncEvent) throws IOException { 
  34.         System.out.println("AppAsyncListener onTimeout"); 
  35.         ServletResponse response = asyncEvent.getAsyncContext().getResponse(); 
  36.         PrintWriter out = response.getWriter(); 
  37.         out.write("TimeOut Error in Processing"); 
  38.     } 
  39.  
  40. }  

其中請注意可以監聽onTimeout事件的使用,可以有效地返回給用戶端出錯的信息。最后來重新改寫下前文提到的測試Servlet的代碼如下:

#p#

  1. AsyncLongRunningServlet.java 
  2. package com.journaldev.servlet.async; 
  3.  
  4. import java.io.IOException; 
  5. import java.util.concurrent.ThreadPoolExecutor; 
  6.  
  7. import javax.servlet.AsyncContext; 
  8. import javax.servlet.ServletException; 
  9. import javax.servlet.annotation.WebServlet; 
  10. import javax.servlet.http.HttpServlet; 
  11. import javax.servlet.http.HttpServletRequest; 
  12. import javax.servlet.http.HttpServletResponse; 
  13.  
  14. @WebServlet(urlPatterns = "/AsyncLongRunningServlet"asyncSupported = true
  15. public class AsyncLongRunningServlet extends HttpServlet { 
  16.     private static final long serialVersionUID = 1L
  17.  
  18.     protected void doGet(HttpServletRequest request, 
  19.             HttpServletResponse response) throws ServletException, IOException { 
  20.         long startTime = System.currentTimeMillis(); 
  21.         System.out.println("AsyncLongRunningServlet Start::Name=" 
  22.                 + Thread.currentThread().getName() + "::ID=" 
  23.                 + Thread.currentThread().getId()); 
  24.  
  25.         request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true); 
  26.  
  27.         String time = request.getParameter("time"); 
  28.         int secs = Integer.valueOf(time); 
  29.         // 如果超過10秒則設置為10秒 
  30.         if (secs > 10000) 
  31.             secs = 10000
  32.  
  33.         AsyncContext asyncCtx = request.startAsync(); 
  34.         asyncCtx.addListener(new AppAsyncListener()); 
  35.         asyncCtx.setTimeout(9000); 
  36.  
  37.         ThreadPoolExecutor executor = (ThreadPoolExecutor) request 
  38.                 .getServletContext().getAttribute("executor"); 
  39.  
  40.         executor.execute(new AsyncRequestProcessor(asyncCtx, secs)); 
  41.         long endTime = System.currentTimeMillis(); 
  42.         System.out.println("AsyncLongRunningServlet End::Name=" 
  43.                 + Thread.currentThread().getName() + "::ID=" 
  44.                 + Thread.currentThread().getId() + "::Time Taken=" 
  45.                 + (endTime - startTime) + " ms."); 
  46.     } 
  47.  

下面運行這個Servlet程序,輸入:

http://localhost:8080/AsyncServletExample/AsyncLongRunningServlet?time=8000,運行結果為:

AsyncLongRunningServlet Start::Name=http-bio-8080-exec-50::ID=124

AsyncLongRunningServlet End::Name=http-bio-8080-exec-50::ID=124::Time Taken=1 ms.

Async Supported? true

AppAsyncListener onComplete

但如果我們運行一個time=9999的輸入,則運行結果為:

AsyncLongRunningServlet Start::Name=http-bio-8080-exec-44::ID=117

AsyncLongRunningServlet End::Name=http-bio-8080-exec-44::ID=117::Time Taken=1 ms.

Async Supported? true

AppAsyncListener onTimeout

AppAsyncListener onError

AppAsyncListener onComplete

Exception in thread "pool-5-thread-6" java.lang.IllegalStateException: The request associated with the AsyncContext has already completed processing.

at org.apache.catalina.core.AsyncContextImpl.check(AsyncContextImpl.java:439)

at org.apache.catalina.core.AsyncContextImpl.getResponse(AsyncContextImpl.java:197)

at com.journaldev.servlet.async.AsyncRequestProcessor.run(AsyncRequestProcessor.java:27)

at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)

at java.lang.Thread.run(Thread.java:680)

可以看到,Servlet主線程很快執行完畢并且所有的處理額外的工作都是在另外一個線程中處理的,不存在阻塞問題。

 原文鏈接:http://www.javacodegeeks.com/2013/08/async-servlet-feature-of-servlet-3.html

責任編輯:陳四芳 來源: 51CTO
相關推薦

2009-07-08 09:35:53

Java ServleServlet 3.0

2009-07-09 11:27:59

Servlet容器

2009-07-07 10:08:49

Future Resp

2009-07-09 13:04:37

Servlet接口

2009-07-09 13:39:52

Servlet Con

2009-07-09 10:49:56

Servlet和JSP

2024-12-10 00:00:30

ServletTomcat異步

2009-07-07 09:41:02

異步ServletAJAX

2010-01-14 09:15:07

Java EE 6Servlet 3.0異步處理

2009-07-07 09:51:49

Servlet實例

2009-07-07 15:24:49

Http Servle

2021-06-02 10:39:59

ServletWebFluxSpringMVC

2009-07-08 11:17:10

Servlet容器Servlet Con

2009-07-09 13:23:44

Servlet 2.4

2009-07-03 11:21:43

Servlet和JSPJSP路徑

2009-07-07 17:32:31

HTTP Servle

2009-07-07 16:05:15

Servlet和Jav

2010-04-30 09:19:05

Servlet 3.0

2009-07-08 14:01:47

Servlet容器

2009-07-08 15:59:55

doFilter方法
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩三区在线 | 亚洲精品国产第一综合99久久 | 久久久久国产一区二区三区不卡 | 国产一区中文字幕 | 国产精品久久久久久久久免费 | 华人黄网站大全 | 在线观看成人精品 | 日本一区二区三区精品视频 | 91精品中文字幕一区二区三区 | 国产精品久久久久久久模特 | 一区二区在线视频 | 一级黄色片美国 | 成人av一区| 成人做爰9片免费看网站 | 日韩欧美三级电影 | 国产精品久久久久久久久免费 | 久久精品视频播放 | 日韩在线播放一区 | 情侣av | 九九看片| 国产精品一区二区三区99 | 成人在线精品视频 | 成人伊人 | 二区成人 | 久久中文字幕电影 | 久热精品在线播放 | 日韩不卡在线观看 | 亚洲一一在线 | 国产精品天堂 | av电影一区二区 | 免费的一级视频 | 中文字幕一区在线观看视频 | 中文字幕第一页在线 | 日韩中文字幕视频在线观看 | 国产成人免费一区二区60岁 | 99re在线视频| 天堂色综合 | 天天射网站 | 国内精品在线视频 | 亚洲精品综合 | 国产视频精品在线观看 |