2014-03-04 117 views
3

我有一个接受请求并写入长响应的servlet。响应处于使用Thread.sleep(1000)模拟长时间运行操作的循环中。我试图在这里设置一个异步请求,如代码所示。但它不起作用。当我向servlet调用多个请求时,它们都是连续执行的,而不是同时执行。我究竟做错了什么?异步servlet不能异步执行

而我通过servlet应该是线程 - 每个请求到服务器导致容器执行一个新的线程(或从池中重用一个)。

package test; 

import java.io.IOException; 
import java.io.PrintWriter; 
import javax.servlet.ServletException; 

import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

import javax.servlet.AsyncContext; 

import javax.servlet.annotation.WebServlet; 

@WebServlet(urlPatterns={"/test"}, asyncSupported=true) 
public class TestServ extends HttpServlet { 

    @Override 
    public void doGet(HttpServletRequest rq, HttpServletResponse rs){ 

     rs.setContentType("text/plain"); 
     rs.setHeader("Access-Control-Allow-Origin", "*"); 


     AsyncContext asy = rq.startAsync(rq, rs); 
     asy.start(new Client(asy)); 
    } 


    @Override 
    public String getServletInfo() { 
     return "Short description"; 
    } 
} 

class Client implements Runnable { 

    private int counter = 0; 
    private AsyncContext asy; 

    Client(AsyncContext asy) { 
     this.asy = asy; 
    } 

    @Override 
    public void run() { 
     //run long task here 
     try { 
      PrintWriter out = asy.getResponse().getWriter(); 
      while (counter < 5) { 

       out.println(counter++ + 1); 
       Thread.sleep(1000); 

      } 

     } catch (Exception ex) { 

     } finally{ 
      asy.complete(); 
     } 
    } 
} 
+1

您是如何设定servlet容器的线程池? – vanza

+0

你如何生成请求到您的Servlet? –

+0

Mark,XMLHttpRequest - “get”。 – user3348039

回答

1

使用方法ExecutorService.execute()产卵在后台线程一些任务。

执行步骤:

  • 阅读来自web.xml中在servlet初始化一些初始化参数()方法,诸如超时而threadpoolsize
    • 超时参数用于设定异步线程的超时
    • threadpoolsize用于通过调用HTTP request.startAsync()中的doGet()或doPost(以创建异步线程
  • 获取AsyncContext池)实现方法具AsyncContext
  • 连接监听器,这个AsyncContext的生命周期事件,如的onComplete(),onTimeout(),onerror的(),onStartAsync()
  • 呼叫ExecutorService.execute(回应)d
  • 超时设置为产卵一些任务在后台线程

试试这个示例代码。它可能会帮助你。

AsyncServletTaskProcessor:

import java.io.IOException; 

import javax.servlet.AsyncContext; 
import javax.servlet.ServletException; 

public interface AsyncServletTaskProcessor { 

    void process(AsyncContext ctx) throws IOException, ServletException; 
} 

TestServ:

import java.io.IOException; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 

import javax.servlet.AsyncContext; 
import javax.servlet.ServletException; 
import javax.servlet.annotation.WebServlet; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

@WebServlet(urlPatterns = { "/test" }, asyncSupported = true) 
public class TestServ extends HttpServlet implements AsyncServletTaskProcessor{ 

    /** The exec. */ 
    private ExecutorService exec; 

    public int CALLBACK_TIMEOUT; 

    public void init() throws ServletException { 
     // read callback timeout form web.xml as init parameter 
     CALLBACK_TIMEOUT = Integer.parseInt(getInitParameter("timeout")); 
     // read thread pool size form web.xml as init parameter 
     int size = Integer.parseInt(getInitParameter("threadpoolsize")); 
     exec = Executors.newFixedThreadPool(size); 

    } 

    @Override 
    public void doGet(HttpServletRequest rq, HttpServletResponse rs) { 

     rs.setContentType("text/plain"); 
     rs.setHeader("Access-Control-Allow-Origin", "*"); 

     //AsyncContext asy = rq.startAsync(rq, rs); 
     //asy.start(new Client(asy)); 

     final AsyncContext asy = rq.startAsync(); 

     // set the timeout 
     asy.setTimeout(CALLBACK_TIMEOUT); 

     // attach listener to respond to lifecycle events of this AsyncContext 
     asy.addListener(new AsyncListenerImpl(asy)); 

     // spawn some task in a background thread 
     exec.execute(new AsyncServletTaskRunner(asy, this)); 
    } 

    @Override 
    public String getServletInfo() { 
     return "Short description"; 
    } 

    @Override 
    public void process(AsyncContext ctx) throws IOException, ServletException { 
     //do whatever you want to do as process of each thread 
    } 
} 

AsyncServletTaskRunner:

import javax.servlet.AsyncContext; 

public class AsyncServletTaskRunner implements Runnable { 

    /** The ctx. */ 
    private AsyncContext ctx; 

    /** The processor. */ 
    private AsyncServletTaskProcessor processor; 

    public AsyncServletTaskRunner() { 
     super(); 
    } 

    public AsyncServletTaskRunner(AsyncContext ctx, AsyncServletTaskProcessor processor) { 
     this.ctx = ctx; 
     this.processor = processor; 
    } 

    @Override 
    public void run() { 

     try { 
      processor.process(ctx); 
     } catch (Exception e) { 
      try { 
       // redirect to error page or do whatever is needed 
      } catch (Exception e1) { 
       e1.printStackTrace(); 
      } 
     } finally { 
      ctx.complete(); 
     } 
    } 

    public AsyncContext getCtx() { 
     return ctx; 
    } 

    public void setCtx(AsyncContext ctx) { 
     this.ctx = ctx; 
    } 

} 

AsyncListenerImpl:

import java.io.IOException; 

import javax.servlet.AsyncContext; 
import javax.servlet.AsyncEvent; 
import javax.servlet.AsyncListener; 

public class AsyncListenerImpl implements AsyncListener { 

    /** The ctx. */ 
    private AsyncContext ctx; 

    public AsyncListenerImpl() { 
     super(); 
    } 

    public AsyncListenerImpl(AsyncContext ctx) { 
     this.ctx = ctx; 
    } 

    @Override 
    public void onComplete(AsyncEvent event) throws IOException { 
     /** complete() has already been called on the async context, nothing to do */ 
    } 

    @Override 
    public void onTimeout(AsyncEvent event) throws IOException { 
     /** timeout has occured in async task... handle it */ 
     try { 
      // redirect to error page or do whatever is needed 
     } catch (Exception e1) { 
      e1.printStackTrace(); 
     } finally { 
      ctx.complete(); 
     } 
    } 

    @Override 
    public void onError(AsyncEvent event) throws IOException { 
     /** THIS NEVER GETS CALLED - error has occured in async task... handle it */ 
     try { 
      // redirect to error page or do whatever is needed 
     } catch (Exception e1) { 
      e1.printStackTrace(); 
     } finally { 
      ctx.complete(); 
     } 
    } 

    @Override 
    public void onStartAsync(AsyncEvent event) throws IOException { 
     /** async context has started, nothing to do */ 
    } 

} 
+0

当然,你需要一个ExecutorService来执行这些线程。从web.xml读取一些参数,例如线程超时和线程池大小。 AsyncListenerImpl实现AsyncListener接口来处理异步监听器的所有进程。 – Braj

+0

尝试了解它,同时我正在用步骤更新我的答案。 – Braj

+0

这不适合我,但谢谢。 –