[英]Asynchronous servlet not acting asynchronously
我有一個servlet接受請求並寫一個長響應。 響應處於一個循環中,該循環使用Thread.sleep(1000)來模擬長時間運行的操作。 我試圖在這里設置一個異步請求,如代碼所示。 但它沒有用。 當我向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();
}
}
}
使用方法ExecutorService.execute()在后台線程中生成一些任務。
要遵循的步驟:
試試這個示例代碼。 它可能對你有幫助。
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 */
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.