异步servlet的不演戏异步 [英] Asynchronous servlet not acting asynchronously
问题描述
我有一个servlet,需要一个请求,并写了一个很长的响应。响应是在使用了Thread.sleep(1000)以模拟长期运行动作的循环。我试图建立一个异步请求在这里,如图code。但它不工作。当调用多个请求到Servlet,他们都执行连续,不能在同一时间。我究竟做错了什么?
和我虽然servlet应该是螺纹 - 每个请求服务器导致执行一个新的线程(或重用一个来自池)容器
封装测试;进口java.io.IOException异常;
进口的java.io.PrintWriter;
进口javax.servlet.ServletException;进口javax.servlet.http.HttpServlet;
进口javax.servlet.http.HttpServletRequest;
进口javax.servlet.http.HttpServletResponse;进口javax.servlet.AsyncContext;进口javax.servlet.annotation.WebServlet;@WebServlet(URL模式= {/测试},asyncSupported = TRUE)
公共类TestServ延伸的HttpServlet { @覆盖
公共无效的doGet(HttpServletRequest的RQ,HttpServletResponse的RS){ rs.setContentType(text / plain的);
rs.setHeader(访问控制允许原产地,*);
AsyncContext ASY = rq.startAsync(RQ,RS);
asy.start(新客户端(ASY));
}
@覆盖
公共字符串getServletInfo方法(){
返回简短说明;
}
}类客户端实现Runnable { 私人INT计数器= 0;
私人AsyncContext ASY; 客户端(AsyncContext ASY){
this.asy = ASY;
} @覆盖
公共无效的run(){
//此处运行长期任务
尝试{
PrintWriter的OUT = asy.getResponse()的getWriter()。
而(计数器小于5){ 通过out.println(计数器++ + 1);
视频下载(1000); } }赶上(例外前){ } {最后
asy.complete();
}
}
}
使用方法 ExecutorService.execute()产卵一些任务在后台线程。
执行步骤:
- 从阅读中的web.xml servlet初始化一些初始化参数()方法,如超时和threadpoolsize
- 超时参数是用来设置异步线程超时
- threadpoolsize用于创建异步线程池
- 获取AsyncContext通过调用HTTP request.startAsync()中的doGet()或doPost()方法
- AsyncContext的设置超时
- 连接监听器,这个AsyncContext的生命周期事件,如的onComplete(),onTimeout(),onerror的(),onStartAsync响应()
- 呼叫ExecutorService.execute()来派生一些任务在后台线程
试试这个样本code。它可以帮助你。
AsyncServletTaskProcessor:
进口java.io.IOException异常;进口javax.servlet.AsyncContext;
进口javax.servlet.ServletException;公共接口AsyncServletTaskProcessor { 无效的过程(AsyncContext CTX)抛出IOException异常,ServletException异常;
}
TestServ:
进口java.io.IOException异常;
进口java.util.concurrent.ExecutorService中;
进口java.util.concurrent.Executors;进口javax.servlet.AsyncContext;
进口javax.servlet.ServletException;
进口javax.servlet.annotation.WebServlet;
进口javax.servlet.http.HttpServlet;
进口javax.servlet.http.HttpServletRequest;
进口javax.servlet.http.HttpServletResponse;@WebServlet(URL模式= {/测试},asyncSupported = TRUE)
公共类TestServ延伸的HttpServlet实现AsyncServletTaskProcessor { / **这位经理。 * /
私人的ExecutorService EXEC; 公众诠释CALLBACK_TIMEOUT; 公共无效的init()抛出了ServletException {
//读取回调超时形式的web.xml的初始化参数
CALLBACK_TIMEOUT =的Integer.parseInt(的getInitParameter(超时));
//读取线程池大小形态web.xml中作为初始化参数
INT大小=的Integer.parseInt(的getInitParameter(threadpoolsize));
EXEC = Executors.newFixedThreadPool(大小); } @覆盖
公共无效的doGet(HttpServletRequest的RQ,HttpServletResponse的RS){ rs.setContentType(text / plain的);
rs.setHeader(访问控制允许原产地,*); // AsyncContext ASY = rq.startAsync(RQ,RS);
//asy.start(new客户端(ASY)); 最终AsyncContext ASY = rq.startAsync(); //设置超时
asy.setTimeout(CALLBACK_TIMEOUT); //连接监听器,这个AsyncContext的生命周期事件作出回应
asy.addListener(新AsyncListenerImpl(ASY)); //产卵一些任务在后台线程
exec.execute(新AsyncServletTaskRunner(ASY,本));
} @覆盖
公共字符串getServletInfo方法(){
返回简短说明;
} @覆盖
公共无效过程(AsyncContext CTX)抛出IOException异常,ServletException异常{
//做任何你想做的事情,因为每个线程的过程
}
}
AsyncServletTaskRunner:
进口javax.servlet.AsyncContext;公共类AsyncServletTaskRunner实现Runnable { / **环磷酰胺。 * /
私人AsyncContext CTX; / **处理器。 * /
私人AsyncServletTaskProcessor处理器; 公共AsyncServletTaskRunner(){
超();
} 公共AsyncServletTaskRunner(AsyncContext CTX,AsyncServletTaskProcessor处理器){
this.ctx = CTX;
this.processor =处理器;
} @覆盖
公共无效的run(){ 尝试{
processor.process(CTX);
}赶上(例外五){
尝试{
//重定向到错误页面,或做任何需要
}赶上(例外E1){
e1.printStackTrace();
}
} {最后
ctx.complete();
}
} 公共AsyncContext getCtx(){
返回CTX;
} 公共无效setCtx(AsyncContext CTX){
this.ctx = CTX;
}}
AsyncListenerImpl:
进口java.io.IOException异常;进口javax.servlet.AsyncContext;
进口javax.servlet.AsyncEvent;
进口javax.servlet.AsyncListener;公共类AsyncListenerImpl实现AsyncListener { / **环磷酰胺。 * /
私人AsyncContext CTX; 公共AsyncListenerImpl(){
超();
} 公共AsyncListenerImpl(AsyncContext CTX){
this.ctx = CTX;
} @覆盖
公共无效的onComplete(AsyncEvent事件)抛出IOException
/ **完成()已经呼吁异步上下文无关* /
} @覆盖
公共无效onTimeout(AsyncEvent事件)抛出IOException
/ **超时发生在异步任务......处理它* /
尝试{
//重定向到错误页面,或做任何需要
}赶上(例外E1){
e1.printStackTrace();
} {最后
ctx.complete();
}
} @覆盖
公共无效的onError(AsyncEvent事件)抛出IOException
/ **这不会被调用 - 错误发生在异步任务......处理它* /
尝试{
//重定向到错误页面,或做任何需要
}赶上(例外E1){
e1.printStackTrace();
} {最后
ctx.complete();
}
} @覆盖
公共无效onStartAsync(AsyncEvent事件)抛出IOException
/ **异步方面已经开始,无关* /
}}
I have a servlet that takes a request and writes a long response. The response is in a loop that uses Thread.sleep(1000) to simulate a long running operation. I am trying to setup an asynchronous request here, as shown in code. But it is not working. When i invoke several requests to the servlet, they all execute consecutively, not at the same time. What am i doing wrong?
And i though servlets are supposed to be threaded - each request to server causes the container to execute a new thread (or reuse one from the pool).
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();
}
}
}
Use method ExecutorService.execute() to spawn some task in a background thread.
Steps to follow:
- Read some init parameters from web.xml in servlet init() method such as timeout and threadpoolsize
- timeout parameter is used to set the timeout of Async thread
- threadpoolsize is used to create a pool of Async threads
- Get AsyncContext by calling HTTP request.startAsync() in doGet() or doPost() method
- Set timeout of AsyncContext
- Attach listener to respond to lifecycle events of this AsyncContext such as onComplete(), onTimeout(), onError(), onStartAsync()
- Call ExecutorService.execute() to spawn some task in a background thread
Try this sample code. It might help you.
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 */
}
}
这篇关于异步servlet的不演戏异步的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!