天天看点

servlet3.0规范异步请求

servlet3.0规范中添加了异步处理,即一部分操作处理完成之后,先行把数据返回来,对于另一部分比较耗时的操作可以放置到另外一个线程中进行处理,该线程保留有连接的请求和响应对象,在处理完成之后可以把处理的结果通知到客户端,实例代码如下:

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;

import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**   
 * @Title: AsynServlet.java 
 * @Package  
 * @Description: TODO
 * @author ynb  
 * @date 2014-7-24 下午5:07:00 
 * @version V1.0   
 */

/**
 * @author admin
 *
 */
@WebServlet(urlPatterns="/demo", asyncSupported=true)
public class AsynServlet extends HttpServlet {
	private static final long serialVersionUID = -8016328059808092454L;
	
	/* (non-Javadoc)
	 * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		  	resp.setContentType("text/html;charset=UTF-8");
	        PrintWriter out = resp.getWriter();
	        out.println("进入Servlet的时间:" + new Date() + ".");
	        out.flush();

	        //在子线程中执行业务调用,并由其负责输出响应,主线程退出
	        final AsyncContext ctx = req.startAsync();
	        ctx.setTimeout(200000);
	        new Work(ctx).start();
	        out.println("结束Servlet的时间:" + new Date() + ".");
	        out.flush();
	}
}

class Work extends Thread{
	private AsyncContext context;
	
	public Work(AsyncContext context){
		this.context = context;
	}
	@Override
	public void run() {
		try {
			Thread.sleep(2000);//让线程休眠2s钟模拟超时操作
			PrintWriter wirter = context.getResponse().getWriter();			
			wirter.write("延迟输出");
			wirter.flush();
			context.complete();
		} catch (InterruptedException e) {
			
		} catch (IOException e) {
			
		}
	}
}
           

有些时候,我们可能需要客户端和服务器保持长连接的时候,我们可以使用这个特性,让服务器长时间保持客户端的请求以及对客户端的响应,做法如下:

对于异步执行,我们可以添加一个监听器,监听异步执行的状态。

ctx.addListener(new AsyncListener() {
				@Override
				public void onTimeout(AsyncEvent arg0) throws IOException {
					// TODO Auto-generated method stub
					
				}
				
				@Override
				public void onStartAsync(AsyncEvent arg0) throws IOException {
					// TODO Auto-generated method stub
					
				}
				
				@Override
				public void onError(AsyncEvent arg0) throws IOException {
					// TODO Auto-generated method stub
					
				}
				
				@Override
				public void onComplete(AsyncEvent arg0) throws IOException {
					// TODO Auto-generated method stub
					
				}
			});
           

在Servlet返回之前,我们可以把持有request和response对象的AsyncContext对象放置到一个全局可访问的静态容器中

map.put("id",ctx);
           

如果连接出错或者连接完的时候我们可以在onError以及onComplete方法中移除掉对应连接的AsyncContext

map.remove("id",ctx);
           

在超时的回调方法onTimeout中,我们可以往浏览器发送指定的信息,让客户端重新发起请求,这样就可以保持客户端和服务器的长久连接。

如下服务器和客户端之间数据交互的模型图

servlet3.0规范异步请求