浏览器的局限性
那么当前的解决方法有什么问题吗?如果应用程序运转正确且允许用户是有生产力的,那么可能没什么错误。但是曾经有很多web开发员抱怨当使用浏览器作为客户机时会限制性能。 这是一些当前开发web应用程序时遇到的问题:
1.浏览器以不一致的方式解释scripting 语言, 譬如Java 语言。 这迫使开发员多次写同样的代码来调节各个浏览器。
2.简单用户接口会影响到譬如选中, 基于向导的表单, 和大表格数据集的处理,这使得在浏览器上需要更多额外的代码。
3.HTML 是有限的,静态的标记语言是无法是扩展的。
4. 在用户接口之内进行事件处理可能是富挑战性的。 因为被反馈的HTML 页一次只能被显示一页, 而事件没有回到服务器之前又是无法更新其它页的。
5. 只能通过Cookie来达到连续的应用状态,Cookie它是不支持对象的。
6.使用浏览器开发偶尔连接的客户机几乎是不可能。
很多Web开发员都知道这个事实: 当前工具设置有局限性。当在浏览器上工作时开发员必须查找解决方法。 对于开发员和用户来说用一台瘦客户机是承受不了当前的性能的。
Rich Internet Applications
为了克服这些局限性, 考虑用RIA来开发。 如今RIA给用户一台胖客户机来扩展浏览器所承受不了的性能。 最普遍应用的J2.EE 的RIA 客户机是Java 和Flash。 当开发大型的数据中心的应用程序时, RIAs 真的是很强的。开发RIA的几个可行方法是JDNC (JDesktop Network Components), Laszlo, Thinlet, Java Web Start, 和Macromedia Flex。
RIA能解决问题前面已经说过了。 下面是RIAs的一些特征:
1. RIAs提供了和浏览器一样的UI组件, 而且它还提供新的本地的更加丰富的组件。 比如包括一个数字步进, 滑动控制, 一个轴向数据网格要素和菜单栏。
2.成熟的RIA应用允许布局管理器由如下构成,譬如制表符浏览器, 折叠,树结构和其它能和AWT and Swing开发相媲美的布局控制。
3.RIAs 提供拖放能力。
4.RIA 里的语言是一致的,它贯穿于所有客户机, 不必为不同的实施而重写。
5.在用户接口,不必每个action都是请求/回应模式。通过富互联网应用,用户与UI 相互对话,如果需要也只需要向服务器发出请求。 RIAs 会运用HTTP 协议方法把数据提交给应用服务器。但是, 通常更好的用RIAs的机制是远程, 它会根据RIA 来支持不同的方式。RIAs提供扩展的与HTTP进行通讯的协议。
6.事件处理横跨多个组件是可能的。
7.RIAs 允许您不使用HttpSession就可以在客户机存储更多信息。 这减少了在应用服务器里所占的内存。
8.状态的连续广播, 通常是以对象的形式,它提供了创建偶尔连接的客户机的可能性。
RIA是相当新的技术,它介绍了开发时涉及到的应用。 它不能解决所有应用, 它是要依赖某种实现。 但是, 如果您认为您的应用可受益于一个更加富有的UI 设计, 那么RIA 也许就可以为您服务。 本文现在将集中于一个RIA 解决方法, Macromedia Flex, 并且集中讨论一下。
Macromedia Flex
Macromedia Flex是RIA的一台商业表示层服务器。因为这是Flex applications.用的环境,所以必需要安装Flash插件。 多数浏览器已经装备了Flash插件,对于RIA来说这也有助于正当使用Flex。 我们来讨论一下不用Java 插件而使用Flash插件来与J2.EE 应用服务器通话的意义所在。
开发员使用二个核心语言创建Flex应用。 第一核心语言是MXML, 即Macromedia Flex Markup Language,它拥有一套丰富的XML 标签,这些标签允许开发员设计用户接口。 MXML 也可以被认为是XUL, 或XML UI 语言。不同于HTML,这些标签是可以扩展的, 它拥有应用程序所需要的额外能力。 其他MXML 结构可以被叫做远程对象, 在model中存储返回的数据, 并且对MXML 构件可以自定义您自己的感观。
第二个Flex开发核心语言是ActionScript 2.0, 它是一个ECMA 支持的语言,与JavaScript 语言类似。 ActionScript 原理是被编码在MXML 页里面的。 这是较强的面向对象的语言,这对于java开发者来说是比较熟悉的。 ActionScript 而且有很大的事件处理能力,它允许应用程序回应动态用户交互。 由于ActionScript 运行在Flash插件里面,所以它不同于在浏览器里进行JavaScript编码,不需要重写几个同样编码的版本来支持不同的浏览器。MXML 和ActionScript 是基于文本的语言, 可以写在一个简单文本编辑器或 一个IDE 工具譬如Eclipse, 或一个更加老练的工具象由Macromedia 公司的Flex Builder里。 如果您接触过Java, XML, 和scripting 语言譬如JavaScript 语言的话, 那么您在学习Flex时就要稍微转下弯了。
Flex服务器负责把MXML 和ActionScript 组件转换成以.SWF 文件的形式的Flash字节码。这个过程类似于用Java Web应用容器把JSP 文件编译成servlets。在Flash运行环境下,SWF 文件被执行在客户机里。 Flex服务器提供其它服务譬如缓存, 并发, 和处理远程对象请求。
给您现有的结构介绍一个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之间传送对象时,需要注意要谨慎的构筑综合性的问题。