彗星http
本系列向您展示如何使用反向Ajax技术开发事件驱动的Web应用程序。 第1部分介绍了反向Ajax,轮询,流传输,Comet和长轮询。 第2部分解释了如何使用WebSockets实现反向Ajax,并讨论了使用Comet和WebSockets的Web服务器的局限性。 第3部分展示了如果需要支持多台服务器或为用户提供独立的Web应用程序以供用户部署在自己的服务器上,则实现自己的Comet或WebSockets通信系统可能会很困难。 即使客户端JavaScript代码很简单,您仍需要一些异常处理,重新连接和确认功能。 在服务器端,缺少全局API和多个Web服务器API导致需要框架,从而带来了抽象。 第3部分还讨论了Socket.IO。
在本文中,了解Atmosphere和CometD。 它们是Java服务器上最广为人知的开源反向Ajax库。
先决条件
理想情况下,要充分利用本文,您应该了解JavaScript和Java。 要运行本文中的示例,您还将需要最新版本的Maven和JDK(请参阅参考资料 )。
大气框架
Atmosphere是一个Java技术框架,提供了用于使用许多Web服务器(包括Tomcat,Jetty,GlassFish,Weblogic,Grizzly,JBossWeb,JBoss和Resin)的Comet和WebSocket功能的通用API。 也支持任何支持Servlet 3.0规范的Web服务器。 在本系列文章中介绍的框架中,Atmosphere支持最多的服务器。
Atmosphere可以检测本机服务器API(适用于Comet和WebSocket),并切换回Servlet 3.0(如果适用)以支持Comet。 或者,同样对于Comet,它将退回到“托管”异步模式(但可扩展性不如Jetty Continuations)。 大气已经存在了两年多,并且仍在积极发展中。 它用于大型Web应用程序中,例如JIRA,它是最著名的问题跟踪器之一。 图1显示了Atmosphere架构。
图1.大气的架构视图
Atmosphere框架由Atmosphere运行时组成,该运行时为所有不同的Web服务器解决方案和标准提供了通用的API。 除此之外,客户端只需设置一个servlet就可以通过Google Web Toolkit(GWT)访问API和Reverse Ajax功能。 或者,您也可以使用Jersey(实现JSR-311(JAX-RS规范)的框架)。 因此,可以在提供额外注释的静态服务中使用Atmosphere。 配置所选模块后,您可以通过实现一些类(在本文后面讨论)来访问Atmosphere运行时。 您还可以选择使用某些提供的插件来添加对集群,消息传递,依赖项注入等的支持。 如果您使用的是Web框架(Wicket,Struts,Spring MVC),则可以使用Atmosphere的MeteorServlet透明地添加反向Ajax支持。 该Servlet公开了一个Meteor
对象,该对象可以在您的控制器和服务中检索以暂停或恢复请求。
Atmosphere的优势仍然在于服务器端:它提供了一个标准化的API,涵盖了所有不同的解决方案以及与WebSockets或Comet进行通信的方式。 Atmosphere不使用客户端和服务器之间的协议,例如Socket.IO和CometD。 这两个库都提供了客户端JavaScript和服务器servlet,它们使用特定的协议(用于握手,消息传递,确认和心跳)进行通信。 Atmosphere的目标是在服务器端提供一个通用的通信通道。 如果需要使用特定协议,例如Bayeux(CometD使用的协议),则必须在Atmosphere中开发自己的“处理程序”。 CometD插件正是这样做的:它利用Atmosphere的API来暂停和恢复请求,并委托给CometD类来使用Bayeux协议管理CometD通信。
Atmosphere附带了一个jQuery客户端库,以简化连接设置,该库能够自动检测可用的最佳传输方式(WebSockets或CometD)。 Atmosphere的jQuery插件的用法类似于HTML5 WebSockets API。 首先,您连接到服务器,注册一个回调以接收消息,然后可以推送一些数据。
本文附带的源代码包含一个Atmosphere示例,该示例直接将处理程序与Atmosphere servlet结合使用。 客户代码始终相同; 它与本系列第1、2和3部分中使用的代码相同(在使用Comet长轮询的聊天示例中)。 您可以使用Atmosphere的jQuery插件,但这不是必需的,因为Atmosphere不执行任何通信协议。 强烈建议您查看Atmosphere项目中的其他示例,尤其是那些使用JSR-311批注的示例(Jersey)。 它们确实简化了处理程序的编写。
清单1显示了Atmosphere处理程序接口。
清单1. AtmosphereHandler
接口
public interface AtmosphereHandler<F, G> {
void onRequest(AtmosphereResource<F, G> resource)
throws IOException;
void onStateChange(AtmosphereResourceEvent<F, G> event)
throws IOException;
void destroy();
}
onRequest
方法接收来自客户端的所有请求,并决定是暂停还是恢复它们(或什么也不做)。 每次暂停或恢复请求,发送广播或发生超时时, onStateChange
方法都会发送和接收事件。
清单2显示了Comet聊天的onRequest
方法的实现。
清单2. AtmosphereHandler
接口onRequest
Broadcaster broadcaster =
BroadcasterFactory.getDefault().lookup(
DefaultBroadcaster.class, ChatHandler.class.getName(), true);
broadcaster.setScope(Broadcaster.SCOPE.APPLICATION);
resource.setBroadcaster(broadcaster);
HttpServletRequest req = resource.getRequest();
String user = (String) req.getSession().getAttribute("user");
if (user != null) {
if ("GET".equals(req.getMethod())) {
resource.suspend(-1, false);
} else if ("POST".equals(req.getMethod())) {
String cmd = req.getParameter("cmd");
String message = req.getParameter("message");
if ("disconnect".equals(cmd)) {
close(resource);
} else if (message != null && message.trim().length() > 0) {
broadcaster.broadcast("[" + user + "] " + message);
}
}
}
典型的约定是挂起GET请求并使用POST请求发送消息。 收到消息后,它将广播到广播公司内注册的所有资源。 请注意,该示例从不向HttpServlet
输出流写入任何内容。 广播或暂停操作仅发送其他实现的方法接收到的事件,如清单3所示:
清单3. AtmosphereHandler
接口onStateChange
Broadcaster broadcaster =
BroadcasterFactory.getDefault().lookup(
DefaultBroadcaster.class, ChatHandler.class.getName(), true);
// Client closed the connection.
if (event.isCancelled()) {
close(event.getResource());
return;
}
try {
String message = (String) event.getMessage();
if (message != null) {
PrintWriter writer =
event.getResource().getResponse().getWriter();
writer.write(message);
writer.flush();
}
} finally {
if (!event.isResumedOnTimeout()) {
event.getResource().resume();
}
}
现在,您拥有进行彗星聊天所需的全部内容。 总而言之,重要的Atmosphere概念是:代表连接的资源对象,以及负责向资源触发事件并决定何时暂停或恢复请求的广播公司。 请注意,该示例仅是Comet。 为了能够使用WebSockets和Comet,应该使用客户端库,并且需要更复杂的处理程序。
表1概述了使用Atmosphere框架的利弊。
表1.大气的利弊
优点 | 缺点 |
---|---|
如果必须在无法控制的多个Web服务器中部署Web应用程序。 由于Atmosphere支持的Web服务器数量众多,因此您更有可能使应用程序的Reverse Ajax功能正常工作。 当您需要通过原始Reverse Ajax通信进行通用API且未定义任何协议时,因为您要开发或扩展它。 | 缺少有关Atmosphere的架构,项目,概念和API的文档,如果您需要进入源代码或分析几个提供的示例,这将很有帮助。 与其他框架(如Socket.IO和CometD)的简单API相比,该API具有很高的技术性,有时甚至是晦涩的。 即使使用Atmosphere批注,某些名称和属性也太技术化。 尽管在服务器端是一个很好的抽象,但是没有一个好的客户端库。 没有协议,因此所有其他功能都留给开发人员。 如果您需要高级超时检测,确认,退避,跨域等等,尤其是在使用移动设备时,当前的库对于大型可伸缩Web应用程序的需求而言太简单了。 在这种情况下,CometD更可靠。 它利用了可用于激活一些控制流和错误检测的通信协议,所有这些都在CometD中提供。 如果需要其他功能,将CometD JavaScript客户端与Atmosphere CometD插件一起使用可能是一个不错的选择。 |
CometD框架
CometD框架是基于HTTP的事件驱动的通信解决方案,已经存在了几年。 版本2增加了对注释配置和WebSockets的支持。 CometD框架提供了Java服务器部分和Java客户端部分,以及基于jQuery和DojoJavaScript客户端库。 CometD使用一种称为Bayeux的标准化通信协议,使您可以激活某些扩展,以进行消息确认,流控制,同步,群集等。
CometD的事件驱动方法非常适合事件驱动的Web开发的新概念。 与传统的桌面用户界面一样,所有组件都通过总线进行通信以发送通知和接收事件。 因此,所有通信都是异步的。
CometD框架:
- 有据可查。
- 提供示例和Maven原型以促进项目的启动。
- 具有精心设计的API,可以进行扩展开发。
- 提供一个称为Oort的群集模块,该模块使您能够将多个CometD Web服务器作为负载平衡器后面的群集中的节点运行,以扩展到更多的HTTP连接。
- 支持安全策略,以允许细粒度配置谁可以通过哪个通道发送消息。
- 与Spring和Google Guice(依赖注入框架)的集成非常好。
贝叶协议
Bayeux通信协议主要基于HTTP。 它异步提供客户端和服务器之间的响应双向通信。 Bayeux协议基于消息路由的通道,这些消息被路由并从客户端到服务器,服务器到客户端或客户端到客户端(但通过服务器)传递。 Bayeux是一种发布-订阅协议。 CometD实现了Bayeux协议,因此在Comet和WebSocket传输之上提供了一个抽象层,以通过Bayeux路由请求。
服务器和内部
CometD与三种传输方式捆绑在一起:JSON,JSONP和WebSocket。 它们取决于Jetty Continuations和Jetty WebSocket API。 默认情况下,CometD可以在Jetty 6、7和8以及支持Servlet 3.0规范的任何其他服务器中使用。 可以通过与扩展相同的方式来添加和开发传输。 您应该能够编写支持Grizzly WebSocket API等的传输,然后在配置CometD服务器的步骤中添加它们。 图2显示了CometD主要块的概述。
图2. CometD的体系结构视图
图2中未显示访问消息通道的安全层。
本文提供的源代码包括一个使用CometD的Web应用程序。 Web应用程序的描述符包含清单4中有关聊天示例的定义。
清单4. web.xml
<servlet>
<servlet-name>cometd</servlet-name>
<servlet-class>
org.cometd.java.annotation.AnnotationCometdServlet
</servlet-class>
<async-supported>true</async-supported>
[...]
<init-param>
<param-name>services</param-name>
<param-value>ChatService</param-value>
</init-param>
<init-param>
<param-name>transports</param-name>
<param-value>
com.ovea.cometd.websocket.jetty8.Jetty8WebSocketTransport
</param-value>
</init-param>
</servlet>
CometD servlet支持一些控制全局设置的选项,例如设置传输和服务的能力。 在该示例中,假设您要添加对Jetty 8的WebSocket支持。服务器端的CometD服务类ChatService
将控制每个人都在讲话的聊天室,如清单5所示:
清单5. CometD ChatService
@Service
public final class ChatService {
@Inject
BayeuxServer server;
@PostConstruct
void init() {
server.addListener(new BayeuxServer.SessionListener() {
@Override
public void sessionAdded(ServerSession session) {
[...]
}
@Override
public void sessionRemoved(ServerSession session, boolean timedout) {
[...]
}
});
}
@Configure("/**")
void any(ConfigurableServerChannel channel) {
channel.addAuthorizer(GrantAuthorizer.GRANT_NONE);
}
@Configure("/chatroom")
void configure(ConfigurableServerChannel channel) {
channel.addAuthorizer(new Authorizer() {
@Override
public Result authorize(
[..] // check that the user is in session
}
});
}
@Listener("/chatroom")
void appendUser(ServerSession remote,
ServerMessage.Mutable message) {
[...]
}
}
清单5展示了CometD的一些重要功能,包括:
- 依赖注入
- 生命周期管理
- 全局通道配置
- 安全管理
- 消息转换(在所有消息之前添加用户名)
- 会话管理
在客户端,该示例未激活任何扩展,仅激活了原始的CometD代码,如清单6所示:
清单6. CometD客户端代码
// First create t cometd object and configure it
var cometd = new $.Cometd('CometD chat client');
cometd.configure({
url: document.location + 'cometd',
logLevel: 'debug'
});
cometd.websocketEnabled = 'WebSocket' in window;
// Then we register some listeners. Meta channels (those with
// the form /meta/<name> are specific reserved channels)
cometd.addListener('/meta/disconnect', function(message) {
[...]
});
cometd.addListener('/meta/connect', function(message) {
[...]
});
// Then, starting a connexion can be done using:
cometd.handshake();
// And subscriptions with:
cometd.subscribe('/chatroom', function(event) {
[...] // event.data holds the message
});
// We finally send data to the chatroom like this:
cometd.publish('/chatroom', msg);
CometD的客户端API易于使用和理解,同时仍然功能强大且可扩展。 本文仅涵盖Web应用程序的主要部分,因此请查看示例应用程序以更好地了解CometD的功能。
表2概述了使用CometD框架的利弊。
表2. CometD的优缺点
优点 | 缺点 |
---|---|
CometD提供了从客户端和服务器端以及从独立Java客户端到服务器的完整解决方案。 该框架文档齐全,具有良好的API,并且易于使用。 最好的是,它具有事件驱动的方法。 CometD和Bayeux是许多事件驱动的Web应用程序的一部分。 其他Reverse Ajax框架不提供任何事件驱动的机制,迫使最终用户开发自己的自定义解决方案。 CometD支持许多必需的功能,例如重新连接,可靠的超时检测,后退,批处理,消息确认以及其他在其他Reverse Ajax框架中找不到的功能。 CometD使您可以实现最可靠,低延迟的通信。 | CometD当前不支持Jetty for Comet(Tomcat)以外的任何Servlet 2.5容器,并且不支持Glassfish / Grizzly WebSocket。 |
结论
Atmosphere和CometD都是可靠的开源反向Ajax解决方案。 在Ovea,我们之所以选择CometD,是因为我们为集群环境中的移动设备开发了可伸缩的事件驱动的Web应用程序,并且我们对基础架构拥有完全的控制权(我们使用Jetty)。 但是,如果没有其他开发,如果您要出售Web应用程序并希望您的Reverse Ajax功能在尽可能多的服务器上运行,CometD可能不是最佳选择。 但是,知道现在有越来越多的Web容器支持Servlet Specification 3.0,CometD的限制趋于减少。 说到传输层,剩下的主要区别现在取决于WebSocket支持。
翻译自: https://www.ibm.com/developerworks/web/library/wa-reverseajax4/index.html
彗星http