AsyncContext簡介


為了支持異步處理,在Servlet 3.0中,在ServletRequest上提供了startAsync()方法: AsyncContext startAsync() throws Java.lang.IllegalStateException; AsyncContext startAsync(ServletRequest servletRequest,                         ServletResponse servletResponse)                         throws java.lang.IllegalStateException

這兩個方法都會返回AsyncContext接口的實現對象,前者會直接利用原有的請求與響應對象來創建AsyncContext,后者可以傳入自行創建的請求、響應封裝對象。在調用了startAsync()方法取得AsyncContext對象之后,此次請求的響應會被延后,並釋放容器分配的線程。

可以通過AsyncContext的getRequest()、getResponse()方法取得請求、響應對象,此次對客戶端的響應將暫緩至調用AsyncContext的complete()或dispatch()方法為止,前者表示響應完成,后者表示將調派指定的URL進行響應。

若要能調用ServletRequest的startAsync()以取得AsyncContext,必須告知容器此Servlet支持異步處理,如果使用@WebServlet來標注,則可以設置其asyncSupported為true。例如: @WebServlet(urlPatterns = "/some.do", asyncSupported = true) public class AsyncServlet extends HttpServlet { ... 如果使用web.xml設置Servlet,則可以在<servlet>中設置<async-supported>標簽為true: ... < servlet>     <servlet-name>AsyncServlet</servlet-name>     <servlet-class>cc.openhome.AsyncServlet</servlet-class>     <async-supported>true</async-supported> < /servlet> ...

如果Servlet將會進行異步處理,若其前端有過濾器,則過濾器亦需標示其支持異步處理,如果使用@WebFilter,同樣可以設置其asyncSupported為true。例如: @WebFilter(urlPatterns = "/some.do", asyncSupported = true) public class AsyncFilter implements Filter{ ...

如果使用web.xml設置過濾器,則可以設置<async-supported>標簽為true: ... < filter>     <filter-name>AsyncFilter</filter-name>     <filter-class>cc.openhome.AsyncFilter</filter-class>     <async-supported>true</async-supported> < /filter> ...

下面示范一個異步處理的簡單例子: AsyncContextDemo  AsyncServlet.java package cc.openhome; import java.io.*; import java.util.concurrent.*; import javax.servlet.*; import javax.servlet.annotation.*; import javax.servlet.http.*; @WebServlet(name="AsyncServlet", urlPatterns={"/async.do"},              asyncSupported = true) public class AsyncServlet extends HttpServlet {     private ExecutorService executorService =                       Executors.newFixedThreadPool(10);     @Override     protected void doGet(HttpServletRequest request,                                  HttpServletResponse response)     throws ServletException, IOException {         response.setContentType("text/html; charset=UTF8");         AsyncContext ctx = request.startAsync();         executorService.submit(new AsyncRequest(ctx));     }     @Override     public void destroy() {          executorService.shutdown();     }    }

首先告訴容器,這個Servlet支持異步處理?,對於每個請求,Servlet會取得其AsyncContext?,並釋放容器所分配的線程,響應被延后。對於這些被延后響應的請求,創建一個實現Runnable接口的AsyncRequest對象,並將其調度一個線程池(Thread pool)?,線程池的線程數量是固定的,讓這些必須長時間處理的請求,在這些有限數量的線程中完成,而不用每次請求都占用容器分配的線程。

AsyncRequest是個實現Runnable的類,其模擬了長時間處理: AsyncContextDemo  AsyncRequest.java package cc.openhome; import java.io.PrintWriter; import javax.servlet.AsyncContext; public class AsyncRequest implements Runnable {     private AsyncContext ctx;     public AsyncRequest(AsyncContext ctx) {         this.ctx = ctx;     }     @Override     public void run() {         try {             Thread.sleep(10000);              PrintWriter out = ctx.getResponse().getWriter();             out.println("久等了...XD");             ctx.complete();             } catch (Exception e) {             throw new RuntimeException(e);         }     } }

請求與響應對象都封裝在AsyncContext中,所以AsyncRequest建構時必須接受AsyncContext實例。范例中以暫停線程的方式來模擬長時間處理?,並輸出簡單的字符串作為響應文字?,最后調用AsyncContext的complete()對客戶端完成響應?。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM