Request异步请求处理PART2
2016-04-17 17:01
435 查看
为什么需要异步请求处理?
当客户端发送一个请求,服务端接受到这个请求,由于该请求在服务器端需要复杂或耗时比较长的处理,有时候需要开启其他线程进行请求的处理。
此时就可以通过使用异步请求处理的功能。
如何在Servlet中使用异步请求处理?
1.首先,在web.xml中的servlet中配置,如果有filter拦截到的servlet需要异步请求处理,则filter配置中也需要配置这个参数。这样才能支持异步请求处理。
<async-supported>true</async-supported>
2.通过request.startAsync()或request.startAsync(request, response)来初始化异步请求上下文对象AsyncContext。
AsyncContext asyncContextOriginal =request.startAsync();
AsyncContext asyncContextWapper =request.startAsync(request, response);
上面两种的取得AsyncContext的区别:
1.request.startAsync();使用的是原始的ServeltReqeust和ServletResponse对象,即没有使用ServletRequestWrapper或ServletResponseWrapper
实例,这样即使过滤器或者其他方面使用了包装器,得到的AsyncContext也是用原始的ServeltReqeust和ServletResponse对象,不会产生包装效果。
2.request.startAsync(request, response);则不一样,参数request,response可以是包装后的,产生包装效果。
3.AsyncContext 介绍
如果Servlet或过滤器的asyncSupported被标示为true,则它们支持异步请求处理,在不支持异步处理的Servlet或过滤器中调用startAsync(),会抛出
IllegalStateException.
当在支持异步处理的Servlet或过滤器中调用请求对象的startAsync()方法时,该次请求会离开容器所分配的线程,这意味这必须响应处理流程会返回,也就是若有
过滤器,也会依序返回(也就是各自完成的doFilter()方法),但最终的响应被延迟。
可以调用AsyncContext的complete()方法完成响应,而后调用forward()方法,将响应转发给别的Servlet/JSP处理。
或者直接使用AsyncContext.dispatcher()或AsyncContext.dispatcher(String path)方法转发。
不可同时调用complete和dispatcher方法
如果对AsyncContext的起始、完成、超时或错误发生等事件有兴趣,可以实现AsyncListener,使用AsyncContext的addListener()方法加入该监听器。
开启异步请求处理
1.filter中设置
2.servlet中设置
主要功能代码
异步处理监听器
转发后的Servlet
当客户端发送一个请求,服务端接受到这个请求,由于该请求在服务器端需要复杂或耗时比较长的处理,有时候需要开启其他线程进行请求的处理。
此时就可以通过使用异步请求处理的功能。
如何在Servlet中使用异步请求处理?
1.首先,在web.xml中的servlet中配置,如果有filter拦截到的servlet需要异步请求处理,则filter配置中也需要配置这个参数。这样才能支持异步请求处理。
<async-supported>true</async-supported>
2.通过request.startAsync()或request.startAsync(request, response)来初始化异步请求上下文对象AsyncContext。
AsyncContext asyncContextOriginal =request.startAsync();
AsyncContext asyncContextWapper =request.startAsync(request, response);
上面两种的取得AsyncContext的区别:
1.request.startAsync();使用的是原始的ServeltReqeust和ServletResponse对象,即没有使用ServletRequestWrapper或ServletResponseWrapper
实例,这样即使过滤器或者其他方面使用了包装器,得到的AsyncContext也是用原始的ServeltReqeust和ServletResponse对象,不会产生包装效果。
2.request.startAsync(request, response);则不一样,参数request,response可以是包装后的,产生包装效果。
3.AsyncContext 介绍
如果Servlet或过滤器的asyncSupported被标示为true,则它们支持异步请求处理,在不支持异步处理的Servlet或过滤器中调用startAsync(),会抛出
IllegalStateException.
当在支持异步处理的Servlet或过滤器中调用请求对象的startAsync()方法时,该次请求会离开容器所分配的线程,这意味这必须响应处理流程会返回,也就是若有
过滤器,也会依序返回(也就是各自完成的doFilter()方法),但最终的响应被延迟。
可以调用AsyncContext的complete()方法完成响应,而后调用forward()方法,将响应转发给别的Servlet/JSP处理。
或者直接使用AsyncContext.dispatcher()或AsyncContext.dispatcher(String path)方法转发。
不可同时调用complete和dispatcher方法
如果对AsyncContext的起始、完成、超时或错误发生等事件有兴趣,可以实现AsyncListener,使用AsyncContext的addListener()方法加入该监听器。
开启异步请求处理
1.filter中设置
<async-supported>true</async-supported>
<filter-mapping> <filter-name>myFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter> <filter-name>myFilter1</filter-name> <filter-class>com.zghw.servlet.demo.MyFilter1</filter-class> <async-supported>true</async-supported> </filter>
2.servlet中设置
<async-supported>true</async-supported>
<servlet> <servlet-name>myRequestServlet2</servlet-name> <servlet-class>com.zghw.servlet.demo.MyRequestServlet2</servlet-class> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> </servlet> <servlet-mapping> <servlet-name>myRequestServlet2</servlet-name> <url-pattern>/myrs2/*</url-pattern> </servlet-mapping>
主要功能代码
package com.zghw.servlet.demo; import java.io.IOException; import javax.servlet.AsyncContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 请求异步处理 可以先释放容器分配给请求的线程与相关资源,减轻系统负担,原先释放了容器所分配线程的请求。 * 其响应将被延后,可以在处理完成(例如长时间运算完成、所需资源以获得)时在对客户端进行响应。 */ public class MyRequestServlet2 extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { boolean isAsyncStarted = request.isAsyncStarted(); f("当前请求是否开启异步?" + isAsyncStarted); boolean isAsyncSupported = request.isAsyncSupported(); f("当前请求是否支持异步?" + isAsyncSupported); if (!isAsyncStarted && isAsyncSupported) { // 把这个请求放入到异步模式中,如多线程,使用原始的request和response即没有包装过的来初始化一个AsyncContext // AsyncContext asyncContextOriginal =request.startAsync(); // 使用包装后的request和response初始化AsyncContext对象 final AsyncContext asyncContextWapper = request.startAsync(request, response); // asyncContextOrigin = request.getAsyncContext(); // 当请求参数时name=张三,使用request.startAsync();取得AsyncContext使用了没有包装的原始的ServeltReqeust和ServletResponse // 得到的参数"张三"是乱码,没有使用MyServletRequestWrapper,虽然filter使用了但并不会起作用 // String // name=asyncContextOriginal.getRequest().getParameter("name"); // 而使用request.startAsync(request, // response);取得AsyncContext使用了包装后的ServeltReqeust和ServletResponse // 解析中文参数"张三"时,使用了MyServletRequestWrapper来转换编码 String name = asyncContextWapper.getRequest().getParameter("name"); // 为请求异步处理添加一个事件监听器 asyncContextWapper.addListener(new MyAsyncListener(), request, response); // 设置超时时间单位毫秒 asyncContextWapper.setTimeout(5000); // 设置一个线程任务到线程池中,并启动该线程异步处理任务 asyncContextWapper.start(new Runnable() { @Override public void run() { try { System.out.println("处理任务开始"); // 模拟任务 Thread.sleep(3000); System.out.println("任务完成"); // 代表request对应的request中请求url或分发的url进行转发 // 如请求/url/A则转向这个URL,了解详情看这个方法上的注释 // asyncContextWapper.dispatch(); // 转发到对应的路径 asyncContextWapper .dispatch("/myAsyncDispatcherServlet"); // 转发的目标路径在设置的ServletContext中 // asyncContextWapper.dispatch(getServletContext(), // "/myAsyncDispatcherServlet"); // 设置异步请求完成,当进行了dispatch转发,这里就不能在使用complete()方法。 // asyncContextWapper.complete(); } catch (InterruptedException e) { e.printStackTrace(); } } }); // 创建AsyncContext是否使用原始的ServletRequest和ServletResponse对象 boolean hasOriginal = asyncContextWapper .hasOriginalRequestAndResponse(); f(hasOriginal); f("" + name); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } static void f(Object obj) { System.out.println(obj); } }
异步处理监听器
package com.zghw.servlet.demo; import java.io.IOException; import javax.servlet.AsyncContext; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; /** * 请求异步处理监听器,监听异步处理启动、完成、超时或错误事件。 * * @author zghw * */ public class MyAsyncListener implements AsyncListener { /** * 请求异步处理启动时触发 */ @Override public void onStartAsync(AsyncEvent event) throws IOException { System.out.println("MyAsyncListener onStartAsync"); ServletRequest req = event.getSuppliedRequest(); ServletResponse res = event.getSuppliedResponse(); AsyncContext asyncContext = event.getAsyncContext(); } /** * 请求异步完成后触发 */ @Override public void onComplete(AsyncEvent event) throws IOException { System.out.println("MyAsyncListener onComplete"); AsyncContext asyncContext = event.getAsyncContext(); ServletRequest req = event.getSuppliedRequest(); ServletResponse res = event.getSuppliedResponse(); String contextPath = (String) req .getAttribute(AsyncContext.ASYNC_CONTEXT_PATH); f(contextPath); String pathInfo = (String) req .getAttribute(AsyncContext.ASYNC_PATH_INFO); f(pathInfo); String queryString = (String) req .getAttribute(AsyncContext.ASYNC_QUERY_STRING); f(queryString); String requestURI = (String) req .getAttribute(AsyncContext.ASYNC_REQUEST_URI); f(requestURI); String servletPath = (String) req .getAttribute(AsyncContext.ASYNC_SERVLET_PATH); f(servletPath); } /** * 请求异步超时触发 */ @Override public void onTimeout(AsyncEvent event) throws IOException { System.out.println("MyAsyncListener onTimeout"); } /** * 请求异步处理失败完成 */ @Override public void onError(AsyncEvent event) throws IOException { System.out.println("MyAsyncListener onError"); } static void f(Object obj) { System.out.println(obj); } }
转发后的Servlet
package com.zghw.servlet.demo; import java.io.IOException; 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("/myAsyncDispatcherServlet") public class MyAsyncDispatcherServlet extends HttpServlet{ static void f(Object obj) { System.out.println(obj); } private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { AsyncContext asyncContext=request.getAsyncContext(); //请求异步dipatcher转发过来的无法获得AsyncContext中的request和response //ServletRequest req = asyncContext.getRequest(); //ServletResponse res = asyncContext.getResponse(); } }
相关文章推荐
- (4.5.4.2)在Android Studio中进行单元测试和UI测试
- iOS学习笔记33-UICollectionView入门
- iOS学习笔记33-UICollectionView入门
- Android 屏幕尺寸、分辨率、像素密度等UI设计参考
- Penguins DbTools数据库管理移植差分工具(EXCEL相关) ver 20160417
- hdu-5667 Sequence(矩阵快速幂+费马小定理+快速幂)
- HDU 5667 Sequence
- easyui使用数据库数据展示导航标题:idea
- iOS开发——纯代码界面(UIViewController和文本类控件)
- UEditor富文本web编辑器
- IOS-UI设置字体属性
- (LeetCode 307) Range Sum Query - Mutable(树状数组讲解)
- NJUST 1925 sequence
- Android 在其他线程中更新UI线程的解决方法
- RequireJS源码初探
- RVO(Return Value Optimization)和NRVO(Named Return Value Optimization)
- hdu 5667 Sequence【费马小定理+矩阵快速幂】
- (LeetCode 307) Range Sum Query - Mutable(Segment Tree)
- hdu 5667 Sequence 矩阵快速幂
- Java常用之String.valueOf、toString、(String)