知识大全 使用Java实现Comet风格的Web应用(二)

Posted 风格

篇首语:学向勤中得,萤窗万卷书。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 使用Java实现Comet风格的Web应用(二)相关的知识,希望对你有一定的参考价值。

使用Java实现Comet风格的Web应用(二)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  CometProcessor 接口要求实现 event 方法 这是用于 Comet 交互的一个生命周期方法 Tomcat 将使用不同的 CometEvent 实例调用 通过检查 CometEvent 的 eventType 可以判断正处在生命周期的哪个阶段 当请求第一次传入时 即发生 BEGIN 事件 READ 事件表明数据正在被发送 只有当请求为 POST 时才需要该事件 遇到 END 或 ERROR 事件时 请求终止

  在清单 的例子中 Servlet 使用一个 MessageSender 类发送数据 这个类的实例是在 servlet 的 init 方法中在其自身的线程中创建 并在 servlet 的 destroy 方法中销毁的 清单 显示了 MessageSender

  清单 MessageSender  private class MessageSender implements Runnable   protected boolean running = true;  protected final ArrayList messages = new ArrayList();  private ServletResponse connection;  private synchronized void setConnection(ServletResponse connection)  nnection = connection;  notify();    public void send(String message)   synchronized (messages)   messages add(message);  log( Message added #messages=  + messages size());  messages notify();      public void run()   while (running)   if (messages size() ==  )   try   synchronized (messages)   messages wait();     catch (InterruptedException e)   // Ignore      String[] pendingMessages = null;  synchronized (messages)   pendingMessages = messages toArray(new String[ ]);  messages clear();    try   if (connection == null)  try  synchronized(this)  wait();     catch (InterruptedException e)  // Ignore      PrintWriter writer = connection getWriter();  for (int j =  ; j < pendingMessages length; j++)   final String forecast = pendingMessages[j] +  ;  writer println(forecast);  log( Writing:  + forecast);    writer flush();  writer close();  connection = null;  log( Closing connection );   catch (IOException e)   log( IOExeption sending message  e);        

  这个类基本上是样板代码 与 Comet 没有直接的关系 但是 有两点要注意 这个类含有一个 ServletResponse 对象 回头看看清单 中的 event 方法 当事件为 BEGIN 时 response 对象被传入到 MessageSender 中 在 MessageSender 的 run 方法中 它使用 ServletResponse 将数据发送回客户机 注意 一旦发送完所有排队等待的消息后 它将关闭连接 这样就实现了长轮询 如果要实现流风格的 Comet 那么需要使连接保持开启 但是仍然刷新数据

  回头看清单 可以发现 其中创建了一个 Weatherman 类 正是这个类使用 MessageSender 将数据发送回客户机 这个类使用 Yahoo RSS feed 获得不同地区的天气信息 并将该信息发送到客户机 这是一个特别设计的例子 用于模拟以异步方式发送数据的数据源 清单 显示了它的代码

  清单 Weatherman  private class Weatherman implements Runnable  private final List zipCodes;  private final String YAHOO_WEATHER =  ;  public Weatherman(Integer  zips)   zipCodes = new ArrayList(zips length);  for (Integer zip : zips)   try   zipCodes add(new URL(YAHOO_WEATHER + zip));   catch (Exception e)   // dont add it if it sucks        public void run()   int i =  ;  while (i >=  )   int j = i % zipCodes size();  SyndFeedInput input = new SyndFeedInput();  try   SyndFeed feed = input build(new InputStreamReader(zipCodes get(j)   openStream()));  SyndEntry entry = (SyndEntry) feed getEntries() get( );  messageSender send(entryToHtml(entry));  Thread sleep( L);   catch (Exception e)   // just eat it  eat it    i++;      private String entryToHtml(SyndEntry entry)  StringBuilder  = new StringBuilder( );   append(entry getTitle());   append( );   append(entry getDescription() getValue());  return  toString();    

  这个类使用 Project Rome 库解析来自 Yahoo Weather 的 RSS feed 如果需要生成或使用 RSS 或 Atom feed 这是一个非常有用的库 此外 这个代码中只有一个地方值得注意 那就是它产生另一个线程 用于每过 秒钟发送一次天气数据 最后 我们再看一个地方 使用该 Servlet 的客户机代码 在这种情况下 一个简单的 JSP 加上少量的 JavaScript 就足够了 清单 显示了该代码

  清单 客户机 Comet 代码

  <%@page contentType= text/  pageEncoding= UTF %> <!DOCTYPE HTML PUBLIC  //W C//DTD HTML   Transitional//EN     >  <>   <head>     <meta  equiv= Content Type  content= text/; charset=UTF >     <title>Comet Weather</title>     <SCRIPT TYPE= text/Javascript >       function go()         var url = //localhost: /WeatherServer/Weather          var request = new XMLHttpRequest();         request open( GET  url  true);         request setRequestHeader( Content Type application/x javascript; );         request onreadystatechange = function()            if (request readyState ==  )              if (request status ==  )               if (request responseText)                  document getElementById( forecasts ) innerHTML = request responseText;                                         go();                    ;         request send(null);            </SCRIPT>   </head>   <body>     <h >Rapid Fire Weather</h >     <input type= button  onclick= go()  value= Go! ></input>     <div id= forecasts ></div>   </body> </> 

  该代码只是在用户单击 Go 按钮时开始长轮询 注意 它直接使用 XMLHttpRequest 对象 所以这在 Internet Explorer 中将不能工作 您可能需要使用一个 Ajax 库解决浏览器差异问题 除此之外 惟一需要注意的是回调函数 或者为请求的 onreadystatechange 函数创建的闭包 该函数粘贴来自服务器的新的数据 然后重新调用 go 函数

  现在 我们看过了一个简单的 Comet 应用程序在 Tomcat 上是什么样的 有两件与 Tomcat 密切相关的事情要做 一是配置它的连接器 二是在 Servlet 中实现一个特定于 Tomcat 的接口 您可能想知道 将该代码 移植 到 Jetty 有多大难度 接下来我们就来看看这个问题

  Jetty 和 Comet

  Jetty 服务器使用稍微不同的技术来支持 Comet 的可伸缩的实现 Jetty 支持被称作 continuations 的编程结构 其思想很简单 请求先被暂停 然后在将来的某个时间点再继续 规定时间到期 或者某种有意义的事件发生 都可能导致请求继续 当请求被暂停时 它的线程被释放

  可以使用 Jetty 的 mortbay util ajax ContinuationSupport 类为任何 HttpServletRequest 创建 mortbay util ajax Continuation 的一个实例 这种方法与 Comet 有很大的不同 但是 continuations 可用于实现逻辑上等效的 Comet 清单 显示清单 中的 weather servlet 移植 到 Jetty 后的代码

  清单 Jetty Comet servlet   public class JettyWeatherServlet extends HttpServlet   private MessageSender messageSender = null;  private static final Integer TIMEOUT =   *  ;  public void begin(HttpServletRequest request  HttpServletResponse response)  throws IOException  ServletException   request setAttribute( oet  Boolean TRUE);  request setAttribute( oet timeout  TIMEOUT);  messageSender setConnection(response);  Weatherman weatherman = new Weatherman(   );  new Thread(weatherman) start();    public void end(HttpServletRequest request  HttpServletResponse response)  throws IOException  ServletException   synchronized (request)   request removeAttribute( oet );  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  ( oet timeout );  boolean resumed = continuation suspend(timeout == null ?   :  timeout intValue());  if (!resumed)   error(request  response);        public void setTimeout(HttpServletRequest request  HttpServletResponse response   int timeout) throws IOException  ServletException   UnsupportedOperationException   request setAttribute( oet 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 规范

  Servlet 规范

  在此 我们不深究 Servlet 规范的全部细节 只看看 Comet servlet 如果在 Servlet 容器中运行 可能会是什么样子 注意 可能 二字 该规范已经发布公共预览版 但在撰写本文之际 还没有最终版 因此 清单 显示的是遵从公共预览规范的一个实现

  清单 Servlet Comet    @WebServlet(asyncSupported=true  asyncTimeout= )  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(   );  async start(weatherman);;    

  值得高兴的是 这个版本要简单得多 平心而论 如果不遵从 Tomcat 的事件模型 在 Jetty 中可以有类似的实现 这种事件模型似乎比较合理 很容易在 Tomcat 以外的容器(例如 Jetty)中实现 只是没有相关的标准

  回头看看清单 注意它的标注声明它支持异步处理 并设置了超时时间 startAsync 方法是 HttpServletRequest 上的一个新方法 它返回新的 javax servlet AsyncContext 类的一个实例 注意 MessageSender 现在传递 AsynContext 的引用 而不是 ServletResponse 的引用 在这里 不应该关闭响应 而是调用 AsyncContext 实例上的 plete 方法 还应注意 Weatherman 被直接传递到 AsyncContext 实例的 start 方法 这样将在当前 ServletContext 中开始一个新线程

  而且 尽管与 Tomcat 或 Jetty 相比都有较大的不同 但是修改相同风格的编程来处理 Servlet 规范提议的 API 并不是太难 还应注意 Jetty 是为实现 Servlet 而设计的 目前处于 beta 状态 但是 在撰写本文之际 它还没有实现该规范的最新版本

  结束语

cha138/Article/program/Java/hx/201311/26942

相关参考

知识大全 为Web应用程序创建测试用例的办法二

为Web应用程序创建测试用例的办法二  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  另一个重要的

知识大全 用Spring Web Flow和Terracotta搭建Web应用

用SpringWebFlow和Terracotta搭建Web应用  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起

知识大全 Struts配置讲解Web应用

Struts配置讲解Web应用  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  Web应用的发布描

知识大全 WEB页面工具语言XML(二)定义

WEB页面工具语言XML(二)定义  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  XML是一个精

知识大全 应用JSF技术详细介绍Web应用程序开发

应用JSF技术详细介绍Web应用程序开发  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  与微软V

知识大全 利用Javascript建立Web应用

利用Javascript建立Web应用  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!文摘本文作者在

知识大全 JODConverter自带的一个Web应用

JODConverter自带的一个Web应用  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  在这

知识大全 怎样用PowerBuilder开发WEB应用

怎样用PowerBuilder开发WEB应用  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  一P

知识大全 MyEclipse搞定hibernate的web应用

MyEclipse搞定hibernate的web应用  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

知识大全 asp.net、IIS和Web应用程序

asp.net、IIS和Web应用程序  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  一个Web