BlazeDS
引言
通过使用HTTPService、WebService、URLLoader及FileReference等组件或类完成与服务器的通信是非常方便和简单的,但它们的缺点是通信数据量较小,如果要传输大量的数据或实现不同对象的序列化传输,则满足不了需求,需要寻找另外一种通信协议,另一种高效的传输协议代替SOAP协议传输的方案,那便是AMF协议。通过AMF协议实现RPC通信功能,则称为AMF-RPC。在Java平台可以使用LCDS或BlazeDS实现AMF-RPC功能。
1.2 概要
无论是哪种服务器端技术都能够很轻松地应用XML,因为XML 完全是一个基于文本的协议。像 XML 这样基于文本的协议的缺点是额外的数据抽象层的编写与维护工作相对很沉重。此外,如果数据需要序列化和反序列化,那么这个数据抽象层在客户端和服务器端都会占用很多资源。
Flash Player 可以支持另外一种传输协议,这个协议能够缓解由基于文本的协议导致的传输瓶颈问题,能够帮助开发者以更简单的方式与服务器交互。这就是 AMF(Action Message Format)。它是一个二进制格式的协议,能够替代用于传输XML的基于文本的协议而在 HTTP 协议之上交换数据。采用 AMF 的应用中,数据抽象层完全可以省去,客户与服务器间的通讯效率比传统的应用基于文本的协议传输要高得多。
BlazeDS中包含了AMF 的 Java 实现,可以用来与服务器端的Java对象远程交互,也可以用来在客户端之间传递消息。开发人员可以借助 BlazeDS 的远程技术简单地调用 POJO、Spring 服务或EJB方法。开发人员可以通过其消息系统从客户端向服务器端发送消息,当然也可从服务器端向客户端发送消息。
BlazeDS 也可以与其他一些消息系统结合使用,比如JMS、ActiveMQ。由于其远程技术与消息系统采用的方式是在 HTTP 协议上传输 AMF 数据,BlazeDS 因此在性能上拥有很大优势,同时也避免了额外的数据抽象层的处理工作。BlazeDS 在很多基于 Java 的应用服务器环境下都能正常工作,这些服务器包括 Tomcat、WebSphere、WebLogic、JBoss 以及 ColdFusion。此外,无论是 web(在 Flash Player 中运行)还是桌面(在Adobe AIR下运行)的 Flex 应用程序中,BlazeDS 的使用都很简单。
LCDS是一个JavaEE服务端组件,用于简化Flex、Flash和AIR应用程序与JavaEE Web应用程序之间的大数据量通信。通过LCDS与服务器端通信,不但可以大大提高通信的效率,而且还能提供传统B/S结构没有的功能。准确地说,LCDS应该是一个代理网关,客户端的Flex应用的程序对服务器端应用程序的请求必须经过该代理网关进行处理,在经过一系列复杂的处理,服务器响应后,再由该代理网关返回给Flex客户端应用程序。
BlazeDS可以看成是LCDS的一个子集,而且是一个开源产品,在一般的项目中完全可以替代LCDS。BlazeDS是一套面向ActionScript的前后台通信框架。在服务器端,BlazeDS以servlet的方式存在于Java应用服务器上。它默认提供三种服务,远程调用、访问代理和消息服务。同时,框架允许用户添加自定义服务。
BlazeDS 为客户端程序连接到服务端数据、并在多个客户端和服务器间传送数据提供了一系列的服务。BlazeDS 实现了客户端之间的实时消息。
一个BlazeDS 应用包括两个部分:一个客户端应用程序和一个服务端的J2EE 程序,架构如下图:
【客户端程序】
BlazeDS 客户端程序通常是一个Flex 或AIR 应用程序。Flex 和AIR 程序使用Flex 组件和BlazeDS 服务器通讯,包括RemoteObject,HTTPService,WebService,Producer 和Consumer组件,HTTPService, WebService,,Producer 和Consumer 组件都是Flex SDK 的一部分。
尽管通常使用Flex 或AIR 开发客户端程序,但也可联合使用Flex,HTML,JavaScript技术。或者用HTML 和JavaScript 通过Ajax client library 与BlazeDS 通讯。
【BlazeDS 服务端】
BlazeDS 服务端运行在J2EE 应用服务器上的WEB 应用中。BlazeDS 包含三个预定义的web 应用,可以作为开发自定义应用的基础。
为现存的J2EE web 应用配置BlazeDS 支持,执行以下步骤:
-
把BlazeDS 及其依赖的jar 包拷贝到WEB-INF/lib 下。
-
修改WEB-INF/flex 目录下有关BlazeDS的配置文件。
-
在WEB-INF/web.xml 文件中定义MessageBrokerServlet 和一个session listener。
1.3 特点
【BlazeDS 核心功能】
BlazeDS 核心功能包括RPC Services 和Messaging Service。
【RPC Services】
远程过程调用(RPC)服务为请求响应的应用而设计,提供了一种很好的访问外部数据的选择。客户端程序使用RPC 服务发送异步请求给远程服务,服务端处理请求请直接返回数据到客户端。可以通过客户端RPC 组件获取数据,客户端组件包括HTTP GET or POST (HTTP services),SOAP (web services),Java objects (remote object services)。
需要提供企业级功能时可以使用RPC 组件,如为不同域间的传输提供代理,客户端认证,RPC 服务白名单,服务端日志,本地化支持,RPC 服务集中管理。通过BlazeDS 的RemoteObject 组件可以访问远程的Java 对象,而不需要将其配置成WebServices。
客户端的RPC 组件调用一个远程服务,该组件将服务端的响应保存为一个容易获得的ActionScript 对象。这种客户端组件包括HTTPService, WebService 和RemoteObject 组件。
注意:可以直接使用Flex SDK 直接调用HTTP 服务或WebService,而不需要通过BlazeDS 代理。但不能在BlazeDS 或ColdFusion 外使用RemoteObject 组件。
【消息服务】
消息服务可以使客户端程序通过往返的消息和服务端异步通讯。消息属性包括:一个唯一的消息ID、多个BlazeDS 消息头、多个自定义的消息头和消息正文。
客户端程序调用消息生产者发送消息,可以在Flex 程序中使用生产者组件定义一个生产者。客户端程序调用消息消费者接受消息,可以在Flex 程序中使用消费者组件定义一个消费者。消费者组件订阅服务端地址,接收消息生产者发生到该地址的消息。
通过JMSAdapter 消息服务可以桥接到内部或外部的JMS 的话题和队列。桥接可以让Flex 客户端程序和Java 客户端程序交换信息。
【服务适配器】
BlazeDS 可以让你访问不同的持久性数据存储和数据库包括JMS,以及其他的数据持久化设备。服务适配器负责对特定的数据存储服务器以相应的方式更新数据。通过适配器架构可以定制集成任何类型的消息或后端存储系统。
【消息基础框架】
BlazeDS 使用以消息为基础的框架在客户端和服务器之间发送往返消息。BlazeDS 在客户端和服务器间使用两种主要的交换模式。第一种模式是请求响应模式:客户端发送一个请求给服务器处理,服务器返回一个包含处理结果的响应给客户端。RPC 服务使用这种模式。
第二种模式是发送订阅模式:当服务端路径发布消息给一系列订阅该地址的客户端,客户端将收到该消息。消息服务使用这种模式推送消息给感兴趣的客户端。消息服务业使用请求响应模式下达命令,发布消息以及和服务器交互数据。
【通道和端点】
客户端使用通道通过网络发送消息,一个通道封装从服务,目的和应用代码解耦出来的消息格式,网络协议,网络状态。通道把消息格式化并翻译成特定的网络格式,传递到服务器上的一个端点。
并且通道对经由其发往服务器的消息强制指定一种规则,对相应的响应也采取该规则。规则对确保客户端和服务器间交互的一致性,可预见的方式非常重要。
通道和服务器上基于Java 的端点通讯。端点重新配置消息为特定协议格式,传递普通的Java 格式的消息给消息中间人,消息中间人确定消息发送到哪儿,并确定到合适的服务终点的路径。
【通道类型】
BlazeDS 包括几种消息通道,包括标准的和安全的动作消息格式(AMF)通道,以及HTTP(AMFX)通道。AMF 和HTTP 通道支持非轮询的请求响应模式和模拟即时消息的客户端轮询模式。AMF和HTTP通道为实时消息提供实时数据流。
2、BlazeDS应用
2.1 准备工作
从官网上下载BlazeDS,选择”Binary”版本。
打开下载的zip文件后,里面会有一个”blazeds.war”文件。再用winrar解压。
2.2 创建Java工程
在Eclipse中新建一个Dynamic Web Project工程”FlexAndJava_Server”。新建包并命名为”com.hebut.java”,然后新建一个HelloWorld类。
HelloWorld.Java的内容如下所示:
package com.hebut.java;
public class HelloWorld {
public String getInfo(String info){
return “服务器:“+info;
}
}
HelloWorld类的内容很简单,通过定义一个getInfo方法接收外部参数,返回字符串”服务器:”与外部参数连接的字符串。Flex客户端调用这个方法获得返回结果。
解压缩”blazeds.war”文件,将解压后的WEN-INF目录复制到Web工程的WebRoot目录下(覆盖原来的WEB-INF目录)。以记事本格式打开”WebRoot\WEB-INF\flex\”目录下的”remoting-config.xml“文件,在文件中定义一个远程服务,这样Flex应用程序才能调用这个远程服务。
在<services>节点下加入<destination>元素,定义一个服务目标,程序如下所示:
<?xml version=“1.0” encoding=“UTF-8”?>
<service id=“remoting-service”
class=“flex.messaging.services.RemotingService”>
<adapters>
<adapter-definition id=“java-object”
class=“flex.messaging.services.remoting.adapters.JavaAdapter”
default=“true”/>
</adapters>
<default-channels>
<channel ref=“my-amf”/>
</default-channels>
<destination id=“HelloWorld”>
<properties>
<source>com.hebut.java.HelloWorld</source>
</properties>
</destination>
</service>
id属性用于定义Flex应用程序可以访问的服务目标,source属性定义该目标所指向的类。这里HelloWorld即代表”com.hebut.java.HelloWorld”类。
至此,服务器端的程序已经开发完成,部署到Tomcat服务器目录中,并启动Tomcat。
2.3 创建Flex工程
在Flex中,实现AMF-RPC应用要通过<mx:RemoteObject>组件完成,使用该组件可以访问应用服务器上的类。定义格式如下:
<fx:Declarations>
<!– 将非可视元素(例如服务、值对象)放在此处 –>
<s:RemoteObject id=”组件ID” destination=”服务目标” 属性=”属性值” >
</s:RemoteObject>
</fx:Declarations>
destination属性指定服务的目标,该属性的值一定要和Java工程的”remoting-config.xml”中的destination的id一样(安装BlazeDS后添加的那一段)。
(1)endpoint:可使开发人员在编译或以编程方式创建ChannelSet时快速指定RemoteObject目标的端点,而无须引用服务配置文件。在实现Java平台下的AMF-RPC应用时,该属性的值指定的格式为”/Java工程名/messagebroker/amf”。
(2)concurrency:指示如何处理对同一服务的多个调用的值,默认值为multiple,表示不取消现有请求,由开发人员负责通过管理事件流确保返回数据的一致性。其他有效值有single(每次只允许在此方法中发出一个请求);last(发出请求可导致客户端忽略任何当前未处理请求的结果或错误)。
(3)requestTimeout:提供对已发送消息的请求超时(以秒为单位)的访问。
(4) showBusyCursor:如果值为true,则在执行服务时显示忙状态光标,默认值为false。
新建一个Flex项目,名称为”FlexAndJava_Client”。
单击”下一步”按钮设置程序的输出目录为Web应用程序目录,”根文件夹”设为Tomcat服务器下的文件夹,如下图所示。
然后设置界面如下所示。
源代码如下:
<?xml version=”1.0″ encoding=”utf-8″?>
<s:Application xmlns:fx=”http://ns.adobe.com/mxml/2009”
xmlns:s=”library://ns.adobe.com/flex/spark”
xmlns:mx=”library://ns.adobe.com/flex/mx” minWidth=”955”
minHeight=”600“>
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
protected function btnSend_clickHandler(event:MouseEvent):void
{
agent.getInfo(txtSend.text);
}
protected function agent_resultHandler(event:ResultEvent):void
{
txtReceive.text=event.result as String;
}
protected function agent_faultHandler(event:FaultEvent):void
{
Alert.show(“失败信息“+event.message.toString());
}
protected function btnClear_clickHandler(event:MouseEvent):void
{
txtSend.text=“”;
txtReceive.text=“”;
}
]]>
</fx:Script>
<fx:Declarations>
<!– 将非可视元素(例如服务、值对象)放在此处 –>
<mx:RemoteObject id=”agent” destination=”HelloWorld”
result=”agent_resultHandler(event)”
fault=”agent_faultHandler(event)”>
</mx:RemoteObject>
</fx:Declarations>
<s:Panel x=”56” y=”129” width=”250” height=”200” title=”客户发送端“>
<s:Button id=”btnSend” x=”146” y=”129” label=”发送”
click=”btnSend_clickHandler(event)”/>
<s:TextArea id=”txtSend” x=”8” y=”11” width=”232” height=”106“/>
<s:Button id=”btnClear” x=”37” y=”130” label=”清空”
click=”btnClear_clickHandler(event)”/>
</s:Panel>
<s:Panel x=”390” y=”129” width=”250” height=”200” title=”客户接收端“>
<s:TextArea id=”txtReceive” x=”10” y=”10” width=”228“/>
</s:Panel>
</s:Application>
演示效果如下: