聂永的博客

记录工作/学习的点点滴滴。

Servlet 3.0笔记之异步拦截器(async filter)的学习

异步Servlet有时需要一个拦截器,但必须是异步的Filter,否则将会报错:
严重: Servlet.service() for servlet [com.learn.servlet3.async.DemoAsyncLinkServlet] in context with path [/servlet3] threw exceptionjava.lang.IllegalStateException: Not supported.
因此异步的Filter拦截异步Servlet,不要搞错。
我们需要预先定义这么一个异步连接,每秒输出一个数字字符串,从0到99,诸如下面HTML字符串:
<div>2</div>
最后输出Done!
给出两个访问地址,一个用于被拦截(/demoAsyncLink),一个用于单独访问(/demoAsyncLink2),便于对照:
/**
* 模拟长连接实现,每秒输出一些信息
*
* @author yongboy
* @date 2011-1-14
* @version 1.0
*/
@WebServlet(
urlPatterns = { "/demoAsyncLink", "/demoAsyncLink2" },
asyncSupported = true
)
public class DemoAsyncLinkServlet extends HttpServlet {
private static final long serialVersionUID = 4617227991063927036L;

protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.setHeader("Cache-Control", "private");
response.setHeader("Pragma", "no-cache");
response.setHeader("Connection", "Keep-Alive");
response.setHeader("Proxy-Connection", "Keep-Alive");
response.setContentType("text/html;charset=UTF-8");

PrintWriter out = response.getWriter();
out.println("<div>Start ...</div>");
out.flush();

AsyncContext asyncContext = request.startAsync(request, response);

new CounterThread(asyncContext).start();
}

private static class CounterThread extends Thread {
private AsyncContext asyncContext;
public CounterThread(AsyncContext asyncContext) {
this.asyncContext = asyncContext;
}

@Override
public void run() {
int num = 0;
int max = 100;
int interval = 1000;

// 必须设置过期时间,否则将会出连接过期,线程无法运行完毕异常
asyncContext.setTimeout((max + 1) * interval);
PrintWriter out = null;

try {
try {
out = asyncContext.getResponse().getWriter();
} catch (IOException e) {
e.printStackTrace();
}

while (true) {
out.println("<div>" + (num++) + "</div>");
out.flush();

if (num >= max) {
break;
}

Thread.sleep(interval);
}
} catch (InterruptedException e) {
e.printStackTrace();
}

if (out != null) {
out.println("<div>Done !</div>");
out.flush();
out.close();
}

asyncContext.complete();
}
}
}
若想让HttpServletResponse包装器发挥包装的效果,须调用带有参数的startAsync(request, response)方法开启异步输出,否则MarkWapperedResponse将不起作用。因为,若不传递现有的request,response对象,将会调用原生的request和response对象。
在tomcat7下面,异步连接超时时间为10000单位,若不指定超时时间,递增的数字不会按照预想完整输出到99。
我们假设需要定义这样一个Filter,为每一次的异步输出的内容增加一个特殊标记:
<!--marked filter-->
<div>2</div>
逻辑很简单,作为示范也不需要多复杂。
再看看一个异步Filter的代码:
/**
* 异步拦截器
*
* @author yongboy
* @date 2011-1-14
* @version 1.0
*/
@WebFilter(
dispatcherTypes = {
DispatcherType.REQUEST,
DispatcherType.FORWARD,
DispatcherType.INCLUDE
},
urlPatterns = { "/demoAsyncLink" },
asyncSupported = true //支持异步Servlet
)
public class AsyncServletFilter implements Filter {
private Log log = LogFactory.getLog(AsyncServletFilter.class);

public AsyncServletFilter() {
}

public void destroy() {
}

public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {

log.info("it was filted now");

MarkWapperedResponse wapper = new MarkWapperedResponse(
(HttpServletResponse) response);

chain.doFilter(request, wapper);
}

public void init(FilterConfig fConfig) throws ServletException {
}
}
很简单,添加上asyncSupported = true属性即可。在上面Filter中包装了一个HttpServletResponse对象,目的在于返回一个定制的PrintWriter对象,简单重写flush方法(不见得方法多好):
/**
* HttpServletResponse简单包装器,逻辑简单
*
* @author yongboy
* @date 2011-1-14
* @version 1.0
*/
public class MarkWapperedResponse extends HttpServletResponseWrapper {
private PrintWriter writer = null;
private static final String MARKED_STRING = "<!--marked filter--->";

public MarkWapperedResponse(HttpServletResponse resp) throws IOException {
super(resp);

writer = new MarkPrintWriter(super.getOutputStream());
}

@Override
public PrintWriter getWriter() throws UnsupportedEncodingException {
return writer;
}

private static class MarkPrintWriter extends PrintWriter{

public MarkPrintWriter(OutputStream out) {
super(out);
}

@Override
public void flush() {
super.flush();

super.println(MARKED_STRING);
}
}
}
在浏览器端请求被包装的/demoAsyncLink链接,截图以及firebug检测截图如下:
 
可以在浏览器内同时请求/demoAsyncLink2前后作为对比一下。

posted on 2011-01-15 19:39 nieyong 阅读(8127) 评论(0)  编辑  收藏 所属分类: Servlet3


只有注册用户登录后才能发表评论。


网站导航:
 

公告

所有文章皆为原创,若转载请标明出处,谢谢~

新浪微博,欢迎关注:

导航

<2011年1月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
303112345

统计

常用链接

留言簿(58)

随笔分类(130)

随笔档案(151)

个人收藏

最新随笔

搜索

最新评论

阅读排行榜

评论排行榜