本文主要介绍Jetty 异步的请求。Jetty Contination可以用来处理大量的时间比较长的连接请求。
http异步请求在Servlet3中已经实现,使用十分方便,通过Request获取异步AsyncContext,然后在上面注册自己的异步监听器AsynListener即可。Tomcat7 和Jetty8以上版本等主流的容器都支持Servlet3的异步请求。具体介绍见http://www.importnew.com/8864.html,详细的Demohttps://github.com/WangErXiao/Servlet3-Async。这里不多介绍Servlet3的异步请求。
Jetty的异步请求的实现模块主要是Continuation。通过continuation机制,HTTP 请求可以被挂起,超时或者异步事件发生后重新开始。Continuation接口包含两个重要的方法是suspend()和resume()。
当调用continuation.suspend()方法时,会把当前servlet的request和相关的response挂起,request的生命周期将被从Servlet.service(ServletRequest, ServletResponse)扩展到容器,response将不会被提交除非有ContinuationThrowable抛出。调用完suspend方法,注册完异步的handler,直接调用return从Servlet.service方法返回,当前的线程就可以去处理其他任务了。
任务处理完之后,通过注册好的回调方法调用continuation.resume()。重新用原来的request和reponse发起请求,并从request中获取结果,通过response返回。
下边是具体的Demo代码:
public class SimpleSuspendResumeServlet extends HttpServlet {
private MyAsyncHandler myAsyncHandler;
//初始化异步处理器
public void init() throws ServletException {
myAsyncHandler = new MyAsyncHandler() {
public void register(final MyHandler myHandler) {
new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(10000);
//设置结果,调用resume方法
myHandler.onMyEvent("complete!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
};
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
final PrintWriter writer = response.getWriter();
final Continuation continuation = ContinuationSupport
.getContinuation(request);
if (continuation.isInitial()) {
sendMyFirstResponse(response);
continuation.suspend(); // always suspend before registration
myAsyncHandler.register(new MyHandler() {
public void onMyEvent(Object result) {
continuation.setAttribute("results", result);
continuation.resume();
}
});
return; // 然后该线程就可以去处理其他任务了
}
if (continuation.isExpired()) {
sendMyTimeoutResponse(response);
return;
}
//Send the results
Object results = request.getAttribute("results");
if(results==null){
response.getWriter().write("why reach here??");
continuation.resume();
return;
}
sendMyResultResponse(response, results);
}
private interface MyAsyncHandler {
public void register(MyHandler myHandler);
}
private interface MyHandler {
public void onMyEvent(Object result);
}
private void sendMyFirstResponse(HttpServletResponse response) throws IOException {
response.setContentType("text/html");
response.getWriter().write("start---------");
response.getWriter().flush();
}
private void sendMyResultResponse(HttpServletResponse response,
Object results) throws IOException {
response.getWriter().write("results:" + results);
response.getWriter().flush();
}
private void sendMyTimeoutResponse(HttpServletResponse response)
throws IOException {
response.getWriter().write("timeout");
}
}
上面代码中的Support,是工厂类,用来生成Continuation。如果当前容器采用的是Servlet3,返回Servlet3Continuation类型的,如果不是返回FauxContinuation类型的。Servlet3Continuation顾名思义是借助Servlet3里的异步机制来实现的,底层的具体实现还是由具体的容器实现,tomcat7,jetty8以上版本都实现Servlet3异步请求功能。FauxContinuation是Continuation阻塞实现方式,主要是针对才非Servlet3的容器,通过ContinuationFilter过滤器,把FauxContinuation添加到request属性中:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
if (_filtered)
{
Continuation c = (Continuation) request.getAttribute(Continuation.ATTRIBUTE);
FilteredContinuation fc;
if (_faux && (c==null || !(c instanceof FauxContinuation)))
{
fc = new FauxContinuation(request);
request.setAttribute(Continuation.ATTRIBUTE,fc);
}
else
fc=(FilteredContinuation)c;
boolean complete=false;
while (!complete)
{
try
{
if (fc==null || (fc).enter(response))
chain.doFilter(request,response);
}
catch (ContinuationThrowable e)
{
debug("faux",e);
}
finally
{
if (fc==null)
fc = (FilteredContinuation) request.getAttribute(Continuation.ATTRIBUTE);
complete=fc==null || (fc).exit();
}
}
}
else
{
try
{
chain.doFilter(request,response);
}
catch (ContinuationThrowable e)
{
debug("caught",e);
}
}
}
END-------------------------------
转发请标注来源http://my.oschina.net/robinyao/blog/406544