request.setAttribute("org.apache.tomcat.comet", Boolean.TRUE);
request.setAttribute("org.apache.tomcat.comet.timeout", TIMEOUT);
messageSender.setConnection(response);
Weatherman weatherman = new Weatherman(95118, 32408);
new Thread(weatherman).start();
}
public void end(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
synchronized (request) {
request.removeAttribute("org.apache.tomcat.comet");
Continuation continuation = ContinuationSupport.getContinuation
(request, request);
if (continuation.isPending()) {
continuation.resume();
}
}
}
public void error(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
end(request, response);
}
public boolean read(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
throw new UnsupportedOperationException();
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
synchronized (request) {
Continuation continuation = ContinuationSupport.getContinuation
(request, request);
if (!continuation.isPending()) {
begin(request, response);
}
Integer timeout = (Integer) request.getAttribute
("org.apache.tomcat.comet.timeout");
boolean resumed = continuation.suspend(timeout == null 10000 :
timeout.intValue());
if (!resumed) {
error(request, response);
}
}
}
public void setTimeout(HttpServletRequest request, HttpServletResponse response,
int timeout) throws IOException, ServletException,
UnsupportedOperationException {
request.setAttribute("org.apache.tomcat.comet.timeout", new Integer(timeout));
}
}
这里最需要注意的是,该结构与Tomcat 版本的代码非常类似。begin、read、end 和error 方法都与Tomcat 中相同的事件匹配。该Servlet 的service 方法被覆盖为在请求第一次进入时创建一个continuation 并暂停该请求,直到超时时间已到,或者发生导致它重新开始的事件。上面没有显示init 和destroy 方法,因为它们与Tomcat 版本是一样的。该servlet 使用与Tomcat 相同的MessageSender。因此不需要修改。注意begin 方法如何创建Weatherman 实例。对这个类的使用与Tomcat 版本中也是完全相同的。甚至客户机代码也是一样的。只有servlet 有更改。虽然servlet 的变化比较大,但是与Tomcat 中的事件模型仍是一一对应的。
希望这足以鼓舞人心。虽然完全相同的代码不能同时在Tomcat 和Jetty 中运行,但是它是非常相似的。当然,JavaEE 吸引人的一点是可移植性。大多数在Tomcat 中运行的代码,无需修改就可以在Jetty 中运行,反之亦然。因此,毫不奇怪,下一个版本的Java Servlet 规范包括异步请求处理(即Comet 背后的底层技术)的标准化。 我们来看看这个规范:Servlet 3.0 规范。
Servlet 3.0 规范
在此,我们不深究Servlet 3.0 规范的全部细节,只看看Comet servlet 如果在Servlet 3.0 容器中运行,可能会是什么样子。注意 “可能” 二字。该规范已经发布公共预览版,但在撰写本文之际,还没有最终版。因此,清单7 显示的是遵从公共预览规范的一个实现。
清单7. Servlet 3.0 Comet
@WebServlet(asyncSupported=true, asyncTimeout=5000)
public class WeatherServlet extends HttpServlet {
private MessageSender messageSender;
// init and destroy are the same as other
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
AsyncContext async = request.startAsync(request, response);
messageSender.setConnection(async);
Weatherman weatherman = new Weatherman(95118, 32444);
async.start(weatherman);;
}
}
值得高兴的是,这个版本要简单得多。平心而论,如果不遵从Tomcat 的事件模型,在Jetty 中可以有类似的实现。这种事件模型似乎比较合理,很容易在Tomcat 以外的容器(例如Jetty)中实现,只是没有相关的标准。
回头看看清单7,注意它的标注声明它支持异步处理,并设置了超时时间。startAsync 方法是HttpServletRequest 上的一个新方法,它返回新的javax.servlet.AsyncContext 类的一个实例。注意,MessageSender 现在传递AsynContext 的引用,而不是