`
lwbbupt
  • 浏览: 35218 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

servlet异步处理中遇到一些问题及其分析

阅读更多

刚开始学习servlet,照着书写了写异步处理的一些例子:

 

@WebServlet(urlPatterns="/async", asyncSupported = true)
public class AsyncServlet extends HttpServlet {
	@Override
	public void service(HttpServletRequest request, HttpServletResponse response) 
			throws IOException, ServletException{
		response.setContentType("text/html; charset = utf-8");
		PrintWriter out = response.getWriter();
		out.println("<title>异步调用测试</title>");
		out.println("进入servlet的时间为:" + new Date() + "<br/>");
		out.flush();
		//创建AsyncContext,开始异步调用
		boolean isasync = request.isAsyncSupported();
		AsyncContext actx = request.startAsync();
		actx.setTimeout(20000);
		Runnable run = new Executer(actx);
		actx.start(new Executer(actx));
		out.println("结束servlet的时间为: " + new Date() + "<br/>");
		out.flush();
	}
}

 

public class Executer implements Runnable{
	private AsyncContext actx = null;
	public Executer(AsyncContext actx){
		this.actx = actx;
	}
	public void run(){
		try{
			Thread.sleep(5000);
			ServletRequest request = actx.getRequest();
			List<String> books = new ArrayList<String>();
			books.add("java学习");
			books.add("javaee 学习");
			request.setAttribute("books", books);
			actx.dispatch("/async.jsp");
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}
}

 

 <body>
    <%
    List<String> books = (List<String>)request.getAttribute("books");
    if(books !=null){
    	for(String book: books){
    		out.println(book);
    		out.println("<br/>");
    	}
    }
    out.println("业务调用时间结束:"+ new Date() + "<br/>");
    request.getAsyncContext().complete();
    %>
  </body>

 先是报了一个这样的错误:

 

 

严重: Servlet.service() for servlet [webDemo.AsyncServlet] in context with path [/webDemo] threw exception [javax.servlet.ServletException: java.lang.IllegalStateException: Cannot create a session after the response has been committed] with root cause
java.lang.IllegalStateException: Cannot create a session after the response has been committed
	at org.apache.catalina.connector.Request.doGetSession(Request.java:2924)
	at org.apache.catalina.connector.Request.getSession(Request.java:2300)
	at org.apache.catalina.connector.RequestFacade.getSession(RequestFacade.java:897)
	at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:229)
	at org.apache.catalina.core.ApplicationHttpRequest.getSession(ApplicationHttpRequest.java:569)

 即:不能在响应提交后,再创建session,分析出现这个问题的原因是由于我们的代码中存在以下语句:

 

response.setContentType("text/html; charset = utf-8");

响应向客户端返回来了http的头文件,导致了不能创建sessionid,因为sessionid一般存在于http cookie

的头文件了,所以为了避免以上问题,我们可以在上面的语句加上一句:

 

HttpSession session = request.getSession();

 先创建session,当然也可以不通过response输出头文件。

 

在解决了这个问题之后程序依然报错

严重: Servlet.service() for servlet [webDemo.AsyncServlet] in context with path [/webDemo] threw exception [java.lang.IllegalStateException: Calling [asyncComplete()] is not valid for a request with Async state [DISPATCHED]] with root cause
java.lang.IllegalStateException: Calling [asyncComplete()] is not valid for a request with Async state [DISPATCHED]
	at org.apache.coyote.AsyncStateMachine.asyncComplete(AsyncStateMachine.java:227)
	at org.apache.coyote.http11.Http11AprProcessor.actionInternal(Http11AprProcessor.java:456)
	at org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:867)
	at org.apache.coyote.Request.action(Request.java:344)
	at org.apache.catalina.core.AsyncContextImpl.complete(AsyncContextImpl.java:91)
	at org.apache.jsp.async_jsp._jspService(async_jsp.java:92)
	at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)

 即:对于处于dispatched异步状态下的request调用asyncComplete()是无效的,分析可知问题出在以下语句:

request.getAsyncContext().complete();

我们删除这条语句,问题解决。

我们在api中关于complete函数找到了以下几句话:

It is legal to call this method any time after a call to ServletRequest.startAsync() or ServletRequest.startAsync(ServletRequest, ServletResponse), and before a call to one of the dispatch methods of this class.

说的很清楚在startAsync之后以及在dispatch方法之前调用是合法的。

在关于dispatch方法的说明中:

There can be at most one asynchronous dispatch operation per asynchronous cycle, which is started by a call to one of the ServletRequest.startAsync() methods. Any attempt to perform an additional asynchronous dispatch operation within the same asynchronous cycle will result in an IllegalStateException. If startAsync is subsequently called on the dispatched request, then any of the dispatch or complete() methods may be called.

在使用了dispatch方法之后只有startAsync方法调用后才能调用complete方法。

 

最后应当注意的是,在使用异步之前最好查看下request是否支持异步操作,即查看boolean isAsyncSupported()

 

Asynchronous operation is disabled for this request if this request is within the scope of a filter or servlet that has not been annotated or flagged in the deployment descriptor as being able to support asynchronous handling.

 

 

 

 

 

1
0
分享到:
评论
2 楼 lwbbupt 2014-05-22  
AsyncContext只是向request添加了books这个属性,然后通过dispatch方法将请求转发到指定的jsp做处理
1 楼 string2020 2014-05-21  
请问,run方法里面的
actx.dispatch("/async.jsp"); 
是什么意思?

既然当前servlet是一直往页面输出的,为何要dispatch一个jsp

相关推荐

Global site tag (gtag.js) - Google Analytics