IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Java technology  >

品味“Bitter Java”: 往返旅程反模式

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 初级

IBM, 作者

2003 年 3 月 01 日

往返旅程反模式

返回原文

一天傍晚,我看着两个女儿收拾她们的玩具。两岁的小女儿卖力地执行着她的任务,从房子中间捡起一个玩具,然后把它拿到墙边的玩具箱。五岁的大女儿却在看电视,这让我有点生气。就在我打算关掉电视机的时侯,节目突然切换到广告。她一下子从沙发上跳下来,将自己所有的玩具都丢进一个篮子,飞快地跑过房间,然后将所有玩具一次倒进玩具箱中。我被眼前的情景逗乐了,然后转过去看小女儿,她还在认真地干着自己的活,每次拿一个玩具。

问题:过多分立的通信

作为一名顾问,我看到过太多和我辛苦的小女儿一样的应用程序。往返过程讲的是在一个类似于分布式边界的昂贵接口上执行某种重复性任务的应用程序。这种反模式使很多不同类型的 Java 程序受到影响。数据库应用程序通常在应用程序中进行过滤、联合和计算,这会迫使应用程序产生过多与数据库服务器的通信。Applet 可以通过单独处理每个域进行服务器端验证。持久性框架会迫使数据搜索在应用程序中进行,而不是在数据库引擎中进行,但在后者中进行数据搜索的效率是前者的好几倍。用户接口框架通常会迫使应用程序为每个元素(如输入域或选单)产生一个分布式通信。

请考虑一个 EJB 应用程序。图 1 展示了一个显示发票的应用程序的模型。为了解决问题,开发者决定使用直接与远程 EJB 实体 bean 进行通信的 JSP 页。请注意,很多文章和书籍都警告读者不要使用这种方法,但很多工具实际上却鼓励人们使用这种类型的 EJB 开发。


图 1. 发票应用程序的模型
发票模型

它可能还不会立刻很清晰,但这种设计展示了一种经典的往返旅程的情况。序列图(如图 2 所示)是检测往返旅程问题的一个很好的直观帮助。这个序列图描述了用户接口和我们的发票应用程序之间的流程。如果我们把 EJB 容器和 JSP 容器部署在分开的机器中,那么我们就会碰到往返旅程问题。注意,在 JSP 和 EJB 模型之间有很多通信。有了序列图,您就可以轻易地看到潜在的问题,不过还是让我们深入到更多细节中去吧。


图 2. 这个序列图展示了往返旅程问题。
序列图。

请考虑 JSP 页显示发票的情况。应用程序获取包含两个域和多个组成项的发票:两个客户(开记帐单和发货的地址)和项目列表(每个项目都包含数量和产品)。下面的表格将计算所需的往返旅程的数目,结果是 10 + 4N,其中 N 表示发票上产品的数目。

对象 内容 往返旅程数 往返旅程总数
发票Id 日期 客户 项目1 + 1 + 8 + 4N =10 + 4N
客户名称 ID 地址1 + 1 + 6 =8
地址(两个地址)Id 街道 城市2 + 2 + 2 =6
项目(N 个项目)数量 产品1N + 3N =4N
产品(N 个项目)ID 名称 价格1N + 1N + 1N =3N

这样得出的数字似乎还不算高,不过让我们来做一点数学运算。对于一个包含 20 个项目的单独发票来说,这个数字算下来就是 10 + 4(20),或者说 4.5 秒钟就有 90 个往返旅程。请牢记我们只是在考虑通信开销。天哪。那么请考虑一下从多个发票中选择其中之一的情况。从我们的序列图中可以得知,开销会迅速增长到无法控制的地步。只要获取 10 个发票,我们就要等待 45 秒。显然,我们必须进行重构。





回页首


重构的解决方案:使用虚包

您很可能知道,处理 EJB 实体 bean 的秘诀就在于将很多重复的操作组成为一个单独的批处理命令。对于 EJB 组件来说,完成这个任务最常用的方式就是使用虚包,也就是一个替代接口。和我的大女儿的篮子一样,虚包也可以将很多小的旅程(如产品号或客户名称)合并为一个对更大的组合对象的请求(如整张发票或发票列表)。虽然传输的字节数还是一样,但虚包极大地减少了往返旅程的总数以及相关的通信开销。您可以使用 EJB 实现构建一个带有返回序列化对象的会话 bean 的虚包。

图 3 展示了我们修改过的序列图。


图 3. 往返旅程较少的序列图
发票模型

JSP 页在 Web 应用程序服务器作出对虚包层的单独请求。虚包代码在服务器端作出所有单独调用,以构建单独的发票,虚包将序列化这个发票并将其返回到客户机。然后,虚包在企业服务器本地查询实体 bean,然后构建一个序列化的对象,它还会将此对象序列化并返回到请求的 servlet。图 3 展示了实际的虚包。注意,我们转移了远程接口边界,这样我们就只有一个单独的分布式通信来获取整个发票了。当然,我们还可以添加一个接口以返回发票的集合。

尽管很多不错的资源都表明直接从客户机访问实体 bean 有危险,但往返旅程反模式还是吸引着很多 Java 程序员。下面这些技巧可以帮助您尽早检测错误并扫清障碍:

  • 在处理象 EJB 组件这样的分布式系统时,请研究和使用成功的设计模式。尽管框架可以处理细节,您还是应该了解分布式计算的基本原理。

  • 请使用序列图来检测和解决昂贵的边界上麻烦的接口问题。

  • 请将多个孤立的请求合并为逻辑分组。

当然,我们的最终目标是消除不必要的往返旅程。虚包策略通过使每个往返旅程更有效率而实现这一点。其它的策略也可以对您有所帮助。高速缓存可以消除对已经获取的数据的往返旅程。提前获取(Fetch-ahead)策略可以在每一块获取多个数据行,从而达到多次使用。不管您选择什么策略,基本的要求是分布式计算很昂贵。那么,就让它们物有所值吧。

返回原文



关于作者

IBM has authored this article




对本文的评价

太差! (1)
需提高 (2)
一般;尚可 (3)
好文章 (4)
真棒!(5)

建议?







回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款