刚开始学习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, ServletResp
onse
)
, 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.
相关推荐
Servlet3.0 异步处理 页面推送 Comet 实例
异步servlet
java servlet 3 异步调用 异步处理 注册监听
Spring+ajax+servlet异步完成登录名是否存在,讲解在https://blog.csdn.net/woshilishu/article/details/84619757.
主要介绍了Java中Servlet3.0异步处理的原理以及遇到的问题分析,需要的朋友参考一下。
3-6Tomcat处理源码实现与异步Servlet源码实现(1).mp4
ajax异步文件上传,servlet处理
主要介绍了详解Servlet 3.0/3.1 中的异步处理,实例分析了servlet 3.0异步处理的技巧,非常具有实用价值,需要的朋友可以参考下
NULL 博文链接:https://dacoolbaby.iteye.com/blog/2163367
ajax异步上传源码,后台servlet处理 改编自http://www.phpletter.com/Demo/AjaxFileUpload-Demo/ 这个后台是PHP版的,我把它改成了JAVA版的
假如一个场景,用户上传文件,某些用户网速较慢,同时存在100个这样的用户,如果BIO且最大线程设为100会导致线程用完。...本实例采用tomcat8作为容器,开启异步servlet读写事件,解决高并发IO传输问题。
介绍JSP常用内置对象,基本动作及其作用,跳转方式等; Servlet生命周期,基本架构等。
servlet与Struts action线程安全问题分析
使用递归方式的easyUI Servlet 异步加载树
理解Servlet的概念以及Servlet的处理流程
servlet与jsp中文乱码处理,详细介绍多种乱码处理方法,包括使用过滤器的方法
在spring 3.2 及以后版本中增加了对请求的异步处理,这篇文章主要介绍了Spring Boot实现异步请求(Servlet 3.0),感兴趣的小伙伴们可以参考一下。
servlet3异步请求,需要安装gradle,执行scripts/gradle-eclipse.bat/sh 然后导入eclipse
NULL 博文链接:https://fanshuyao.iteye.com/blog/1688318