您的位置:首页 > 产品设计 > UI/UE

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中设置
<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();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: