给您现有的结构介绍一个RIA 框架
现在你对RIA 概念的已经有些了解了, 让我们看看怎么把RIA 引入到您现有的结构中去。 其中我们也将着重论述怎样把RIA表现在一个层状应用中。 此外, 也会讲到当用Flex与一些普遍的公开的框架的结合开发时存在的一些潜在的问题。 这些实例将有助于引入RIA 到您的结构中去。
就让我们先由辨认层状结构开始。一个结构可能包括以下几层: 表示层, 业务代表层,业务综合服务层, 和持久层。 这是各自层的基本实现:
Flex + Business Delegates + Spring Framework + Hibernate
接下去的内容将集中讲解每一层。
我现有的MVC 表示层是怎么样的?
在Web应用程序中表示层是用来给用户传递用户界面, 处理后端服务请求, 并且存储信息数据模型用的。对刚接触RIA的开发员最初可能会倾向于重新使用现有的Struts。 但是, 象Flex这些开发产品都提供了他们自己的MVC 结构。 难道您真地需要维护一个包括二个MVC 结构的表示层吗?
以下是当Flex客户机通过Struts组件向Java 服务器作出请求时的实例。在被更高层接收之前,Flex客户机的请求会先被发送到Struts表示框架。 图1 显示了哪些是不做的:
图1 。怎样不集成Flex and Struts和其它Java组件。
表示框架譬如Struts是由HTTP传送HTML 请求来运行的。 当用Flex客户机来使用HTTP 协议时, 开发员就会出于对性能和面向对象的优点考虑,通过HTTP来使用远程对象而反对提交请求的方式。 所以, 有序化的使用这两个表示框架会提供协议配错。 除非您有特定需要直接地用RIA来集成Strut ,这样才可以避免。 图2 显示一个当使用Flex 和 Struts时更好的解决方法
图2 。 介绍Flex 和 Struts与其它Java 组件
图2 建议怎么安排分离的Flex组件 和 Struts组件共存。 但这是有条件的,这需要在当应用程序请求并行RIA 组件和轻量Struts组件的时候。
开发员应该运用RIA 客户机来做点什么。对于那些熟悉页面请求应答模式的传统Web开发员来说,这是一个明确的思想上的转变。象Flex这样的RIA 产品并非像Struts一样是请求或回应驱动。 RIA 客户机负责在任何情况下更新UI而不必回到服务器。
当使用RIA时Struts不只是您唯一想的事了。 熟悉这类型技术需要时间。 在经历这些曲折以后, 最大的问题是Java服务器端组件的综合化。 这也并非是针对RIA概念。
Flex与业务层集成
前面我们已经讨论了一些表示层相关的,下面我们讨论其它层在我们的应用结构是怎么受影响的。我们已经重置了我们的表示层组件; 我们怎么把它与业务层集成在一起呢?
Flex是一个可扩展的RIA 框架,它提供了很多方式与您的J2.EE 组件通信。Flex提供了HTTP 通信,万维网服务通信,还有Macromedia 的私有的AMF (ActionScript 传讯格式化) 网关。AMF 网关是一个高性能二进制协议,它近似于Flash remoting协议。远程对象运用HTTP 协议被发送到AMF 网关。Flex为每个这些通信协议提供MXML 标签, 这样一来极大的减少编制程序复杂度。 此外, Flex允许您以或异步或同步方式对您的企业等级启用远程调用。 通过使用一种异步远程购买权, 用户就能够对客户机进行一些操作并且即使当发生在传统万维网应用中时也不被拦截。 您能阻拦用户与使用同步调用的UI交涉。
让我们来考虑一下怎么让Flex和我们的业务综合化层集成呢。 为这我们将使用Spring框架作为我们的综合化层, 但这对您选择实施什么综合化层并没有限制。让我们假设一下您有您的服务运行在Spring microcontainer里, 并且您需要由Flex调用远程对象。
因为Flex对Spring完全不了解,您也许可以考虑添加一个separate, 即一个薄层作为代表您的service components。 并且, 因为Spring对Java接口起到了很大作用,所以我们可以建立一个代表对象,这个代表对象实施着和Spring服务一样的Java 界面。 这些代表对象将提供一个减弱了的网关,它从Flex和综合化层中分离。 您需要做的唯一的事是在Flex配置文件中配置这些对象因此他们能与AMF 网关共同操作。 这里有一个实例将说明代表对象是怎样被配置在server-side flex-config.xml Flex配置文件里的:
<object name="OrderBusinessDelegate">
<source>
com.meagle.flexro.FlexBusinessDelegate
</source>
<type>stateless-class</type>
<use-custom-authentication>
true
</use-custom-authentication>
<allow-unnamed-access>
false
</allow-unnamed-access>
<roles>
<role>OrderUser</role>
<role>Admin</role>
</roles>
</object>
初看Flex你会发现它一些有附加能力,类似于像设置安全性啦,决定委派对象是否申明啦。当Flex发一个远程的对象呼叫到内层时,它将会干扰一个Flex的委派Java对象.委派对象将会负责对呼叫内层或者服务层 (比如Spring).作为结果的对象将通过AMF网关返回到Flex客户端,这个对象被称为ActionScript对象.这里是一个MXML代码的例子, Flex客户端用MXML代码来远程调用并将结果存储到一个数据模式中.
<mx:RemoteObject id="soapro"
named="OrderBusinessDelegate"
protocol="https"
showBusyCursor="true">
<mx:method name="saveNewOrder"
result="saveNewOrder_result(event)"
fault="faultHandler(event.fault)"/>
<mx:method name="findOrderById"
result="findOrderById_result(event)"
fault="faultHandler(event.fault)"/>
<mx:method name="updateOrder"
result="updateOrder_result(event)"
fault="faultHandler(event.fault)"/>
</mx:RemoteObject>
<mx:Model id="roModel" >
<!-- The object graph for the Order object
will be stored here -->
<Order/>
</mx:Model>
用ActionScript equivalents写的Java的域对象在AMF网关里来回传递。这个过程开始于一个请求,这个请求是从Flex服务器通过AMF网关到应用程序的其他层。一个返回对象的图,将会被通过其他Java层,最后通过一个AMF网关返回到服务器。一旦这个对象通过网关他们就将被转变为ActionScript equivalents。图3详细说明了这一过程:
图3. Overview of the AMF gateway.
更多关于在Flex 和Java tier之间的来回传递对象的说明是: 因为ActionScript 2.0 是一种面向对象的语言, 它是可能生成有Java equivalents的ActionScript 对象的。这使在AMF网关之间来回地传递对象变得比较容易和一致。被送回到Flash 插件的 ActionScript 对象类似数据传送对象(DTO) 。这是必要的因为这个Flash 插件没有任何Java 运行时间构成要素。下面是一个用Java写成的一个Order domain object的一个熟悉例子:
package com.meagle.bo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* This object represents an order.
* @hibernate.class table="TestOrder"
* @author meagle
*/
public class Order {
private int id;
private double total;
private int version;
private String userName;
private List orderLineItems = new ArrayList();
// other fields and getter/setter methods not
// shown to save space
}
Here is the ActionScript equivalent:
/**
* Generated Action Script Object
* for com.meagle.bo.Order. Do not edit!
*/
class com.meagle.bo.Order extends Object {
public function Order(){}
public static var regClass =
Object.registerClass("com.meagle.bo.Order",
com.meagle.bo.Order);
var id : Number;
var orderLineItems : Array = new Array();
var total : Number;
var userName : String;
var version : Number;
// other fields and getter/setter methods not
//shown to save space
}
在ActionScript Order对象里你应该注意Object.registerClass这个特别方法。AMF 网关用这个Object.registerClass 方法在Java 和 ActionScript之间来拆整对象。这个方法把客户端的ActionScript 类注册到对服务器端的Java 类。因 为这些对象是很相似的,所以你在一个稍微不同的格式里不想重写你的域对象也是可理解的。像XDoclet 和蚂蚁之类的工具允许你自动地产生这 些ActionScript 对象而不是手动地编码。现在你能像在Flex客户里的ActionScript equivalents操作你的Java对象了
Flex与持久层集成
在使用一个在web上定义好的耦合的体系结构的应用程序中,你不直接和你的持久层对话。使用Flex不应该改变这个体系结构。在大部分情况下,集成层将代替你和你的持久层对话。通常是使用Data Access Object (DAO)来完成的. Data Access Object (DAO) 是用来连接诸如数据库的永久存储的数据的。Flex客户端不直接访问集成层甚至不直接了解这个层,因为它构筑了一个紧密的联结。让我们用Hibernate来作为持久层的一个例子。
当在Macromedia's AMF gateway环境下使用Hibernate和远程对象时,会有一对错误。Hibernate用户知道你不能访问一个不含有已初始化Hibernate会话对象的集合。访问一个没有被初始化的动态代理对象的集合会导致运行时错误。The AMF 网关不知道如何特定的去寻找Hibernate动态代理对象。一个潜在的方法是面向方面的编程(AOP)。即将一个即将传送给AMF网关的对象作为委代对象,移除动态代理。这是一个包含传递结果对象给拦截器,反复寻找使用映射并没有被初始化的代理对象的过程。如果找到什么无用的代理对象或集合,将他们设置为null。这是一个cross-cutting关注,可以作为一个方面,进而使用AOP语言,比如JBoss AOP, AspectJ, Spring AOP等等。AOP拦截器应该被应用于业务代理层的对象。
图4显示的一个应用架构:
图4在代理对象传入AMF网关之前介绍了AOP拦截器 这进一步在高层减少了重复组件,比如集成层,持久层等等。
值得庆幸的是AMF网关不知道缓存双向对象,所以无限的递归循环不会在传送对象时发生。因此,在AMF网关上互相传递对象时,你可以完全保持这种关系。同时,因为对象是非连接的,并且会有拷贝,你需要使用Session.saveOrUpdateCopy(Object object)方法去保存一个对象。这个方法必须使用,因为被传回到AMF网关的对象不会在字节码信息上加入对Hibernate有益的信息。
验证
典型的J2EE web应用程序有许多种身份验证模式。它有可能是基于容器的身份验证模式,或者是一些自定义密码的用户验证。像Flex之类的RIA 服务器允许你在大多数的应用程序服务器上使用Flash客户端的自定义身份验证格式和基于容器的身份验证。此外,如果你看一看上面的业务授权结构的例子的话,你会发现,为了安全起见你可以分配任务给这些对象。甚至在AMF网关中还有很多异常分支,允许开发者们获取HttpRequest、HttpResponse和ServletConfig对象来改进您想使用的、带有授权对象的安全性。
总结
这篇论文引入了一些概念,目的是为了让您了解当您使用诸如Flex之类的RIA时的权衡和潜在的缺陷。不论你使用的是Flex还是其它的RIA工具,在构筑应用程序的时候都会考虑最重要的是什么。当评估一个RIA框架时,要确定它有足够的可扩充性来对应应用程序的需求。此外,在RIA和Java之间传送对象时,需要注意要谨慎的构筑综合性的问题。