java.lang.IllegalStateException: The request associated with the AsyncContext ha
程序员文章站
2022-07-15 16:35:17
...
在使用Servlet3.0的异步特性时,免不了会遇到下面这个异常
具体为什么会产生呢,一直没想过。今天大概看了下代码,原因是这样的:
假设我们的Servlet代码如下,异步的逻辑在Executor中。
此时,由于应用服务器(Tomcat)的异步超时时间默认为10秒,
而异步线程中会睡眠30秒,当30秒之后,会执行
这个ctx.getResponse()方法会判断此时的request是否为空,代码如下:
所以,为了避免该问题,方法有二:
一,在异步Servlet的代码中执行的逻辑时间要小于配置的异步超时时间,
二,在应用服务器中将该时间增大
java.lang.IllegalStateException: The request associated with the AsyncContext has already completed processing. at org.apache.catalina.core.AsyncContextImpl.check(AsyncContextImpl.java:521) at org.apache.catalina.core.AsyncContextImpl.getResponse(AsyncContextImpl.java:245)
具体为什么会产生呢,一直没想过。今天大概看了下代码,原因是这样的:
假设我们的Servlet代码如下,异步的逻辑在Executor中。
AsyncContext ctx = req.startAsync(); new Thread(new Executor(ctx)).start(); class Executor implements Runnable { private AsyncContext ctx = null; public Executor(AsyncContext ctx){ this.ctx = ctx; } public void run(){ try { //等待三十秒钟,以模拟业务方法的执行 System.out.println("进入线程处理时间:"+new Date()); Thread.sleep(30000); PrintWriter out = ctx.getResponse().getWriter();//这一步一般会抛出异常 System.out.println("结束线程处理时间"); out.println("业务处理完毕的时间:" + new Date() + "."); out.flush(); ctx.complete(); } catch (Exception e) { e.printStackTrace(); } }
此时,由于应用服务器(Tomcat)的异步超时时间默认为10秒,
此代码位于Request.java类中。会获取通道配置的异步超时时间 asyncContext.setTimeout(getConnector().getAsyncTimeout());
而异步线程中会睡眠30秒,当30秒之后,会执行
ctx.getResponse().getWriter()
这个ctx.getResponse()方法会判断此时的request是否为空,代码如下:
@Override public ServletResponse getResponse() { check(); return servletResponse; } private void check() { if (request == null) { // AsyncContext has been recycled and should not be being used throw new IllegalStateException(sm.getString( "asyncContextImpl.requestEnded"));//此处即为抛出的异常 } }
所以,为了避免该问题,方法有二:
一,在异步Servlet的代码中执行的逻辑时间要小于配置的异步超时时间,
二,在应用服务器中将该时间增大