Blazeds体系结构
一个Blazeds应用包含了一个运行在浏览器或者Adobe AIR的客户端应用并且和J2EE应用服务端通信。客户端可以是Flex也可以是结合Flex、HTML/JavaScript的应用程序。
整个体系主要包括通道、端点、消息、
Blazeds体系结构
一个Blazeds应用包含了一个运行在浏览器或者Adobe AIR的客户端应用并且和J2EE应用服务端通信。客户端可以是Flex也可以是结合Flex、HTML/JavaScript的应用程序。
整个体系主要包括通道、端点、消息、服务、目的地、适配器等,把这些搞懂也就差不多了。通道使得组件能够和Blazeds服务端的端点通信,将请求送到目的地。端点和通道是相互映射的。
1.Blazeds客户端体系结构
Blazeds使用一个基于消息的框架与服务端结合。这个框架使用通道封装了Flex程序和Blazeds服务端之间的连接。下面是Blazeds客户端的结构
以下Flex组件和Blazeds服务端结合:
. RemoteObject
• HTTPService
• WebService
• Producer
• Consumer
所有的这些组件都包含在Flexsdk和rpc.swc组件库中。
尽管RemoteObject、Producer、Consumer包含在Flexsdk中,他们仍然需要一个服务端来反编译出他们发送的消息。Blazeds和livecycle Data Services ES服务就是两个这样的服务端。当然Flex应用程序可以不使用Blazeds这种中间层而是直接使用HTTP Service或者Web Service来调用远程服务
2.0 通道和通道设置
Flex组件使用通道和Blazeds服务端交互。一条通道包含多条道路,他们的基础功能就是提供Flex客户端和Blazeds服务端的交流。通道中的道路都是按性能排序的。Flex组件会尝试连接第一条道路,不过这并不能保证一定能连接,有可能使用的还是道路中后面的那几条。它会搜寻通道中的道路知道连接上或者已经没有连接。
通道封装了Flex组件和Blazeds服务端之间的连接方式。概念上来说,通道是Flex组件下面的组件,他们处理组件和Blazeds服务端之间的交互。他们和Blazeds服务端上相应的端点通信。
Flex客户端使用不同的通道类型。例如AMFChannel和HTTPChannel。通道选择有很多的因素,包括你的程序构建的类型。如果你想要使用无二进制压缩的方式传输,可以使用HTTPChannel,它使用AMFX(AMF in XML),一种无二进制压缩的方式。
下面的例子在services-config.xml文件中创建了一个AMFChannel通道,与服务器上的AMFEndpoint通信:
<channels>
<channel-deFinition id="samples-amf" class="mx.messaging.channels.AMFChannel">
<endpoint url="http:// servername:8400/myapp/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-deFinition>
</channels>
2.1为flex组件指定通道
如果你通过-services选项指定services-config.xml文件来编译MXML文件,那么组件(RemoteObject、HTTPService等等)会自动指定一个或者多个通道配置实例。
不过如果你没有加这个编译参数,或者想自己覆写编译项的行为,那么你可以在MXML或者AS文件中为组件指定通道。当你想要为你的组件使用动态目的地的时候,整个应用级别的默认通道非常重要。
通过加上-services编译参数,可以包含所有的客户端连接服务器需要的信息,但是一下情况你可能会选择手动设置通道:
1) 你不想硬编码端点路径在你编译的客户端swf文件。
2) 你想要动态的创建目的地(目的地不在services-config.xml文件内)。
3) 你想要在客户端代码控制组件使用通道的顺序。
<RemoteObject id="ro"destination="Dest">
<mx:channelSet>
<mx:ChannelSet>
<mx:channels>
<mx:AMFChannel id="myAmf"
uri="http://myserver:2000/myapp/messagebroker/amf"/>
</mx:channels>
</mx:ChannelSet>
</mx:channelSet>
</RemoteObject>
private function run():void {
ro = new RemoteObject();
var cs:ChannelSet = new ChannelSet();
cs.addChannel(new AMFChannel("myAmf",
"http://servname:2000/eqa/messagebroker/amf"));
ro.destination = "Dest";
ro.channelSet = cs;
}
注意:当你在客户端代码创建通道时,还是必须在services-config.xml文件里配置一个指定端点的通道。否则,messagebroker就不能床底客户端请求到端点。
2.2 为目的地指定通道和端点
如果大多数的目的地使用使用相同的通道,你可以指定应用级别的默认通道,比如:
<services-config...>
...
<default-channels>
<channel ref="my-http"/>
<channel ref="my-amf"/>s
</default-channels>
...
也可以单独指定通道,比如:
<destination id="sampLeverbose">
<channels>
<channel ref="my-secure-amf"/>
</channels>
...
</destination>
2.3 选择端点
可以参考文档或者看blazeds通道、端点配置
消息
Flex客户端组件和Blazeds服务端都是基于消息进行交流的,Flex组件使用几种消息和他们对应的服务交流。所有的消息有基于客户端的(ActionScript)和基于服务端(Java)的,因为这些消息分别在客户端和服务端序列化和反序列化。
一些消息,比如应答消息和命令消息,使用不同的Flex组件和Blazeds服务。其他的消息类型使用特殊的Flex组件和Blazeds服务。例如消息生产者发送消息给消息消费者组件。
其他情况下,你不可以直接写代码构造和发送消息。例如,你只是使用远程组件(RemoteObject)调用远程方法远。远程组件创建一个远程消息封装给远程对象调用。返回的消息封装在一个ResultEvent中。
Blazeds服务端体系
Blazeds服务就是一个包含J2EE Web应用程序的应用。Flex客户端通过通道发送请求到Blazeds服务的端点上。从端点开始,请求经过一些列的Java对象包括消息传播对象、服务对象、目标对象以及最终的适配器对象。适配器将请求实现为本地的、或者contacting a backend system或者远程服务例如JMS服务。下面展示了Blazeds服务体系
端点
基于服务的端点是通过MessagebrokerServlet启动的,需要在web.xml中配置的。除此之外,HTTP session监听器也要加入到web程序的web.xml中。
<!-- Messagebroker Servlet -->
<servlet>
<servlet-name>MessagebrokerServlet</servlet-name>//servlet名称
<display-name>MessagebrokerServlet</display-name>
<servlet-class>flex.messaging.MessagebrokerServlet</servlet-class>//servlet对应类
<init-param> //初始化参数
<param-name>services.configuration.file</param-name> //参数名:services配置文件
<param-value>/WEB-INF/flex/services-config.xml</param-value>//参数值:配置文件相对地址
</init-param>
<load-on-startup>1</load-on-startup>//启动后装载
</servlet>
*********************************************************
*在servlet的配置当中,<load-on-startup>1</load-on-startup>的含义是:
*标记容器是否在启动的时候就加载这个servlet。
*当值为0或者大于0时,表示容器在应用启动时就加载这个servlet;
*当是一个负数时或者没有指定时,则指示容器在该servlet被选择时才加载。
*正数的值越小,启动该servlet的优先级越高。
*********************************************************
<!-- Http Flex Session attribute and binding listenersupport -->
<listener>
<listener-class>flex.messaging.HttpFlexSession</listener-class>
</listener>
客户端程序使用通道和Blazeds端点通信。端点和通道是相互映射的,保持端点和通道使用相同的消息格式是很重要的。如果通道使用AMF消息格式,比如AMFChannel,端点也必须AMF消息格式与之匹配,比如AMFEndpoint。
你可以在WEB-INF/flex目录下的services-config.xml配置端点。
Messagebroker
Messagebroker是为了将消息路由给服务端,是Blazeds在服务端的核心。在端点经过初步的处理请求并且将提炼出来的消息传递给Messagebroker。Messagebroker查看消息的目的地,然后将他传递过去。如果目的地有安全现在,他就在传递之前运行检查证明。
服务和目的地
服务和目的地是消息在Blazeds服务中传递处理的下一站。系统包括4个服务以及他们对应的目的地:
RemotingService(远程服务) 和 RemotingDestination(远程目的地)
HTPProxyService(HTTP代理服务) and HTTPProxyDestination(HTTP代理目的地)
MessageService(消息服务) and MessageDestination(消息目的地)
服务是消息传递过来的目标,可以将目的地想象成服务的实例。例如,远程组件和远程服务通信中,你必须指定一个远程目标,例如你要调用的类的方法。这种客户端和服务端的映射是按照下面来实现的:
HTTPService 和 WebService HTTPProxyService/HTTPProxyDestination通信
RemoteObject和 RemotingService/RemotingDestination通信
Producer、Consumer和 MessageService/MessageDestination通信
你可以在sevices-confi.xml中配置服务和目的地,但是最好是将他们放进不同的文件:
RemotingService配置在remoting-confi.xml
HTTPProxyService配置在proxy-config.xml
MessageService配置在messaging-config.xml
适配器和”随机”的编译是消息处理链中的最后一环。当一个消息抵达正确的目的地以后,它就会被传递给适配器被实现成本地的或者后台系统或者一个远程服务(JMS)。Blazeds使用如下的方式在适配器和目的地间映射
RemotingDestination uses JavaAdapter
HTTPProxyDestination usesHTTPProxyAdapter or SOAPAdapter
MessageDestination usesActionScriptAdapter or JMSAdapter
服务端FlexClient、MessageClient、FlexSession类的实例代表了Flex应用和服务端的连接。你可以使用这些对象管理FLEX应用程序和服务端的同步。
FlexClient,MessageClient,and FlexSession objects
FlexClient
每一个MXML或者AS的Flex应用都被编译进SWF文件。当SWF文件和Blazeds服务通信的时候,一个flex.message.client.FlexClient对象就被创建,并在服务端代表这个SWF文件。SWF文件和FlexClient实例具有一对一的映射关系。Blazeds服务端为每个FlexClient实例生成一个唯一的标识id。在客户端也有一个单例类mx.message.FlexClient,用于存储这个唯一的FlexClient Id。
MessageClient
如果某个Flex应用程序含有一个订阅组件(flex.message.Consumer),服务端就会创建一个相应的flex.messaging.MessageClient实例来代表这个订阅者的发布者。每个MessageClient都有一个唯一的clientId,可以自动由Blazeds服务端生成,也可以在调用Consumer.subscribe()方法之前指定这个Consumer.clientId属性。
FlexSession
FlexSession对象代表在Flex程序和Blazeds服务之间的连接。它的生命周期基于通道和端点使用的底层协议。如果是基于HTTP的通道,例如AMFChannel或者HTTPChannel,在Blazeds服务端就是浏览器范围。如果它连接的端点是一个基于servlet的端点,那么这个HTTPsession是基于J2EE HttpSession 对象。
三者之间的关系
一个FlexObject对象可以拥有多个FlexSession实例,这取决于Flex应用使用的通道数。例如,一个程序使用了一个HTTPChannel,那么在Blazeds服务端一个FlexSession代表这个HTTP session就会被创建。
一个FlexSession也可以拥有一个或多个FlexClient和它关联。例如,a SWF file that uses an
HTTPChannelis opened in two tabs,在BlazeDS服务端2个FlexClient实例被创建(一个SWF文件一个),但是只有一个FlexSession,因为两个tab共享同一个HTTP session。
每个订阅组件都会创建MessageClient。每一个MessageClient都会和一个FlexClient以及一个FlexSession关联。
理解:一个channel对应一个FlexSession,一个SWF文件实例对应一个FlexClient,多个请求会创建多个SWF文件实例,服务端也将创建多个FlexClient对应每一SWF文件,但只有一个FLexSession被创建(假设他们都是用一个HTTPChannel通信)
关于三者的监听器
BlazeDS服务端提供了下列监听器,来让你根据自己的逻辑来创建、销毁、以及改变三者的状态。
FlexClientListener |
|
FlexClientAttributeListener |
|
FlexClientBindingListener |
|
FlexSessionListener |
|
FlexSessionAttributeListener |
|
FlexSessionBindingListener |
|
MessageClientListener |
|
数据序列化
AS对象转换为Java对象
Java对象转换为AS对象
// Product.as
package samples.externalizable {
import flash.utils.IExternalizable;
importflash.utils.IDataInput;
importflash.utils.IDataOutput;
[RemoteClass(alias="samples.externalizable.Product")]
public classproduct implements IExternalizable {
public function Product(name:String=null) {
this.name = name;
}
public var id:int;
public var name:String;
public var properties:Object;
public var price:Number;
public function readExternal(input:IDataInput):void {
name = input.readobject() as String;
properties = input.readobject();
price = input.readFloat();
}
public function writeExternal(output:IDataOutput):void {
output.writeObject(name);
output.writeObject(properties);
output.writeFloat(price);
}
}
}
// Product.java
package samples.externalizable;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Map;
public class Product implements Externalizable {
private String inventoryId;
public String name;
public Map properties;
public float price;
public Product(){
}
public String getInventoryId() {
return inventoryId;
}
public void setInventoryId(String inventoryId) {
if (inventoryId != null &&inventoryId.startsWith("X")){
this.inventoryId = inventoryId;
}else{
throw new IllegalArgumentException("3rd party product
inventory identities must start with 'X'");
}
}
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
name = (String)in.readobject();
properties = (Map)in.readobject();
price = in.readFloat();
setInventoryId(lookupInventoryId(name,price));
}
public void writeExternal(ObjectOutput out) throws IOException {
// Write out the client properties from the serverrepresentation
out.writeObject(name);
out.writeObject(properties);
out.writeFloat(price);
}
private static String lookupInventoryId(String name,floatprice) {
String inventoryId = "X" + name + Math.rint(price);
return inventoryId;
}
}
服务、目的地、适配器等,把这些搞懂也就差不多了。 通道使得组件能够和Blazeds服务端的端点通信,将请求送到目的地。 端点和通道是相互映射的。
1. Blazeds客户端体系结构
Blazeds使用一个基于消息的框架与服务端结合。这个框架使用通道封装了Flex程序和Blazeds服务端之间的连接。下面是Blazeds客户端的结构
以下Flex组件和Blazeds服务端结合:
. RemoteObject
• HTTPService
• WebService
• Producer
• Consumer
所有的这些组件都包含在Flexsdk和rpc.swc组件库中。
尽管RemoteObject、Producer、Consumer包含在Flexsdk中,他们仍然需要一个服务端来反编译出他们发送的消息。Blazeds和livecycle Data Services ES服务就是两个这样的服务端。当然Flex应用程序可以不使用Blazeds这种中间层而是直接使用HTTP Service或者Web Service来调用远程服务
2.0 通道和通道设置
Flex组件使用通道和Blazeds服务端交互。一条通道包含多条道路,他们的基础功能就是提供Flex客户端和Blazeds服务端的交流。通道中的道路都是按性能排序的。Flex组件会尝试连接第一条道路,不过这并不能保证一定能连接,有可能使用的还是道路中后面的那几条。它会搜寻通道中的道路知道连接上或者已经没有连接。
通道封装了Flex组件和Blazeds服务端之间的连接方式。概念上来说,通道是Flex组件下面的组件,他们处理组件和Blazeds服务端之间的交互。他们和Blazeds服务端上相应的端点通信。
Flex客户端使用不同的通道类型。例如AMFChannel和HTTPChannel。通道选择有很多的因素,包括你的程序构建的类型。如果你想要使用无二进制压缩的方式传输,可以使用HTTPChannel,它使用AMFX(AMF in XML),一种无二进制压缩的方式。
下面的例子在services-config.xml文件中创建了一个AMFChannel通道,与服务器上的AMFEndpoint通信:
<channels>
<channel-deFinition id="samples-amf" class="mx.messaging.channels.AMFChannel">
<endpoint url="http:// servername:8400/myapp/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-deFinition>
</channels>
2.1为flex组件指定通道
如果你通过-services选项指定services-config.xml文件来编译MXML文件,那么组件(RemoteObject、HTTPService等等)会自动指定一个或者多个通道配置实例。
不过如果你没有加这个编译参数,或者想自己覆写编译项的行为,那么你可以在MXML或者AS文件中为组件指定通道。当你想要为你的组件使用动态目的地的时候,整个应用级别的默认通道非常重要。
通过加上-services编译参数,可以包含所有的客户端连接服务器需要的信息,但是一下情况你可能会选择手动设置通道:
1) 你不想硬编码端点路径在你编译的客户端swf文件。
2) 你想要动态的创建目的地(目的地不在services-config.xml文件内)。
3) 你想要在客户端代码控制组件使用通道的顺序。
<RemoteObject id="ro"destination="Dest">
<mx:channelSet>
<mx:ChannelSet>
<mx:channels>
<mx:AMFChannel id="myAmf"
uri="http://myserver:2000/myapp/messagebroker/amf"/>
</mx:channels>
</mx:ChannelSet>
</mx:channelSet>
</RemoteObject>
private function run():void {
ro = new RemoteObject();
var cs:ChannelSet = new ChannelSet();
cs.addChannel(new AMFChannel("myAmf",floatprice) {
String inventoryId = "X" + name + Math.rint(price);
return inventoryId;
}
}