Servlet3.0: 简介AsyncContext

每个请求来到Web容器,Web容器会为其分配一条执行绪来专门负责该请求,直到回应完成前,该执行绪都不会被释放回容器。 执行绪会耗用系统资源,若有些请求需要长时间处理(例如长时间运算、等待某个资源),就会长时间占用执行绪,若这类的请求很多,许多执行绪都被长时间占用,对于系统就会是个效能负担,甚至造成应用程式的效能瓶颈。 


基本上一些需长时间处理的请求,通常客户端也较不在乎请求后要有立即的回应,若可以,让这类请求先释放容器分配给该请求的执行绪,让容器可以有机会将执行绪资源分配给其它的请求,可以减轻系统负担。 原先释放了容器所分配执行绪的请求,其回应将被延后,直到处理完成(例如长时间运算完成、所需资源已获得)再行对客户端的回应。 

在Servlet 3.0中,在ServletRequest上提供了 startAsync( )方法: 

 

 

 

Java代码  收藏代码
  1. AsyncContext startAsync() throws java.lang.IllegalStateException;   
  2.   
  3. AsyncContext startAsync(ServletRequest servletRequest,   
  4. ServletResponse servletResponse)   
  5. throws java.lang.IllegalStateException  

 这两个方法都会传回AsyncContext介面的实作物件,前者会直接利用原有的请求与回应物件来建立AsyncContext ,后者可以让你传入自己建立的请求、回应包裹物件。 在呼叫了startAsync()方法取得AsyncContext物件之后,这次的回应会被延后,并释放容器所分配的执行绪。 

 


你可以透过AsyncContext的getRequest() 、 getResponse()方法取得请求、回应物件,此次对客户端的回应将暂缓至呼叫AsyncContext的complete()方法或dispatch()为止,前者表示回应完成,后者表示将回应调派给指定的URL  

若要能呼叫ServletRequest的startAsync()使用AsyncContext,你的 Servlet 必须能支援非同步处理,如果使用@WebServlet来标注,则可以设定其asyncSupported为true 。 例如:

 

Java代码  收藏代码
  1. @WebServlet(urlPatterns = "/some.do", asyncSupported = true )   
  2. public class AsyncServlet extends HttpServlet {   
  3. ...   

 

 如果使用web.xml设定Servlet,则可以设定<async-supported>标签为true :

 

Xml代码  收藏代码
  1. ...   
  2. <servlet>   
  3. <servlet-name>AsyncServlet</servlet-name>   
  4. <servlet-class>cc.openhome.AsyncServlet</servlet-class>   
  5. <async-supported>true</async-supported>   
  6. </servlet>   
  7. ...   

 

 如果Servlet将会非同步处理,若其前端有过滤器,则过滤器亦需标示其支援非同步处理,如果使用@WebFilter ,同样是可以设定其asyncSupported为true 。 例如: 

 

Java代码  收藏代码
  1. @WebFilter(urlPatterns = "/some.do", asyncSupported = true )   
  2. public class AsyncFilter implements Filter{   
  3. ...   

 

 如果使用web.xml设定过滤器,则可以设定<async-supported>标签为true : 

 

Xml代码  收藏代码
  1. ...   
  2. <filter>   
  3. filter -name>AsyncFilter</ filter -name>   
  4. filter -class>cc.openhome.AsyncFilter</ filter -class>   
  5. <async-supported>true</async-supported>   
  6. </ filter >   
  7. ...   

 

 底下示范一个非同步处理的例子,对于进来的请求,Servlet会取得其AsyncContext ,并释放容器所分配的执行绪,回应被延后,对于这些被延后回应的请求,建立一个Runnable的物件,并将其排入一个执行绪池(Thread pool),执行绪池的执行绪数量是固定的,让这些必须长时间处理的请求,在这些有限数量的执行绪中完成,而不用每次请求都占用容器所分配的执行绪。 

 

 

Java代码  收藏代码
  1. package cc.openhome;   
  2.   
  3.   import java.io.*;   
  4.   import java.util.concurrent.*;   
  5.   import javax.servlet.*;   
  6.   import javax.servlet.annotation.*;   
  7.   import javax.servlet.http.*;   
  8.   
  9.   @WebServlet(name="AsyncServlet", urlPatterns={"/async.do"},   
  10.   asyncSupported = true )   
  11.   public class AsyncServlet extends HttpServlet {   
  12.   // 执行绪池   
  13.   private ExecutorService executorService = Executors.newFixedThreadPool(10);   
  14.   
  15.   protected void processRequest(HttpServletRequest request,   
  16.   HttpServletResponse response)   
  17.   throws ServletException, IOException {   
  18.   response.setContentType("text/html; charset=UTF8");   
  19.   AsyncContext ctx = request.startAsync();   
  20.   executorService.submit(new AsyncRequest(ctx));   
  21.   }   
  22.   
  23.   @Override   
  24.   protected void doGet(HttpServletRequest request,   
  25.   HttpServletResponse response)   
  26.   throws ServletException, IOException {   
  27.   processRequest(request, response);   
  28.   }   
  29.   
  30.   @Override   
  31.   protected void doPost(HttpServletRequest request,   
  32.   HttpServletResponse response)   
  33.   throws ServletException, IOException {   
  34.   processRequest(request, response);   
  35.   }   
  36.   
  37.   @Override   
  38.   public void destroy() {   
  39.   executorService.shutdown();   
  40.   }   
  41.   }   

 

 AsyncRequest是个实作Runnable的类别,其模拟了长时间处理: 

 

Java代码  收藏代码
    1. package cc.openhome;   
    2.   
    3.   import java.io.PrintWriter;   
    4.   import javax.servlet.AsyncContext;   
    5.   
    6.   public class AsyncRequest implements Runnable {   
    7.   private AsyncContext ctx;   
    8.   
    9.   public AsyncRequest( AsyncContext ctx ) {   
    10.   this.ctx = ctx;   
    11.   }   
    12.   
    13.   @Override   
    14.   public void run() {   
    15.   try {   
    16.   // 模拟长时间的处理   
    17.   Thread.sleep(10000);   
    18.   PrintWriter out = ctx.getResponse() .getWriter();   
    19.   out.println("久等了...XD");   
    20.   // 这边才真正送出回应   
    21.   ctx.complete();   
    22.   } catch (Exception e) {   
    23.   e.printStackTrace();   
    24.   }   
    25.   }   
    26.   }  

posted @ 2016-02-22 14:56  kabibo  阅读(560)  评论(0编辑  收藏  举报