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

developerWorks 中国  >  Java technology  >

EJB 最佳实践: 用值对象加速您的 RMI 事务

保持 EJB 技术的所有优点而不增加 RMI 开销

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 初级

Brett McLaughlin (brett@oreilly.com), 作家兼编辑, O'Reilly and Associates

2002 年 11 月 20 日

EJB 组件的一个比较常见的用途是在关系型数据管理领域。与 RMI 结合起来,EJB 组件让您不必钻研 JDBC 就可以从关系数据库访问数据。但这种抽象是要付出代价的:RMI 很慢,通常是极慢。那么,窍门就是找到一种方法来保持 EJB 技术的所有优点而又没有使用 RMI 的巨大开销。在这篇技巧文章中,您将看到值对象(也称为 对象映射)是如何帮助您绕开最严重的 RMI 速度障碍的。您将首先从一个工作示例开始,然后了解代码是怎样工作的。

简单实体 bean

考虑一个名为 DVDs的简单数据库表。这个表有几列: idtitlereleaseDateproducer(通过外键)和 director(也是通过外键)。因为我们正在使用 EJB 组件,所以表由实体 bean 表示,并且每个列都有其自己的取值(accessor)方法和赋值(mutator)方法。清单 1 显示了我们的 DVD 表的远程接口:


清单 1. DVD 远程接口
import com.ibm.ejb;
import java.rmi.RemoteException;
import java.util.Date;
import javax.ejb.EJBObject;
public interface DVD extends EJBObject {
      public int getId() throws RemoteException;
      public String getTitle() throws RemoteException;
      public void setTitle(String title) throws RemoteException;
      public Date getReleaseDate() throws RemoteException;
      public void setReleaseDate(Date releaseDate) throws RemoteException;
      public Person getProducer() throws RemoteException;
      public void setProducer(Person producer) throws RemoteException;
      public Person getDirector() throws RemoteException;
      public void setDirector(Person director) throws RemoteException;
}

这里的问题是如何访问表数据,可能一次访问所有数据。为进行一次 DVD 销售或搜索,在线商店或清单应用程序很可能要求获取上述列中包含的大多数或所有信息。为了访问所有信息,应用程序为每列调用一个取值方法 ― 共有五次方法调用,每次都会多占用一点 RMI 通信时间。这种情况再加上其它复杂性,如可能的错误情况、网络流量和相关问题,以及数据的指数级数量(大多数此类表有 15 行或更多),我们的应用程序随时都可能崩溃。

这时就需要值对象。值对象是简单的 Java 类,可以用它来表示多种对象,包括关系数据库行中的数据。通过直接使用值对象,而不是反复使用 bean 的远程接口,我们可以将 RMI 通信减少到一次方法调用。





回页首


创建值对象

清单 2 中的值对象看起来和我们的远程接口几乎相同,但它实际上是具体类。注:通常用 bean 的名称加上 Info 来表示值对象。


清单 2. DVD 值对象
package com.ibm.ejb;
import java.io.Serializable;
import java.util.Date;
public class DVDInfo implements Serializable {
      private int id;
      private String title
      private Date releaseDate;
      private Producer producer;
      private Director director;
      public int getId() {
          return id;
      }
      void setId(int id) {
          this.id = id;
      }
      public String getTitle() {
          return title;
      }
      public void setTitle(String title) {
          this.title = title;
      }
      public Date getReleaseDate() {
          return releaseDate;
      }
      public void setReleaseDate(Date releaseDate) {
          this.releaseDate = releaseDate;
      }
      public Person getProducer() {
          return producer;
      }
      public void setProducer(Person producer) {
          this.producer = producer;
      }
      public Person getDirector() {
          return director;
      }
      public void setDirector(Person director) {
          this.director = director;
      }
}

您应该看出这个类的两个特点。首先,它实现了 java.io.Serializable 。任何可以被实体 bean(或任何其它 EJB 组件)返回的对象都必须满足这个要求。其次,该类中没有方法能够抛出 RMI RemoteException 。这个对象不需要 RMI 通信(这是本练习的全部要点!),因此不会发生 RemoteException 。否则,值对象就成为 bean 的远程接口的翻版了。





回页首


添加两个新方法

创建值对象类是我们的 RMI 解决方案的第一个部分。第二个部分是将两个有价值的方法添加到我们的远程接口,如清单 3 所示:


清单 3. 已修改的 DVD 远程接口
import com.ibm.ejb;
import java.rmi.RemoteException;
import java.util.Date;
import javax.ejb.EJBObject;
public interface DVD extends EJBObject {
      public DVDInfo getInfo() throws RemoteException;
      public void setInfo(DVDInfo info) throws RemoteException;
      public int getId() throws RemoteException;
      public String getTitle() throws RemoteException;
      public void setTitle(String title) throws RemoteException;
      public Date getReleaseDate() throws RemoteException;
      public void setReleaseDate(Date releaseDate) throws RemoteException;
      public Person getProducer() throws RemoteException;
      public void setProducer(Person producer) throws RemoteException;
      public Person getDirector() throws RemoteException;
      public void setDirector(Person director) throws RemoteException;
}

接下来,也是最后一步,在我们的 bean 的实现类中实现 getInfo()setInfo() 这两个新方法,如清单 4 所示:


清单 4. 已修改的 DVD 远程接口
      // Rest of class excluded for brevity
      public DVDInfo getInfo() throws RemoteException {
          DVDInfo info = new DVDInfo();
          // Load value object with current variable values
          info.setId(this.id);
          info.setTitle(this.title);
          info.setReleaseDate(this.releaseDate);
          info.setProducer(getProducer());
          info.setDirector(getDirector());
          return info;
      }
      public void setInfo(DVDInfo info) throws RemoteException {
          setTitle(info.getTitle());
          setReleaseDate(info.getReleaseDate());
          setProducer(info.getProducer());
          setDirector(info.getDirector());
      }





回页首


“魔术”是如何实现的

我们的应用程序需要能够访问来自 DVDs 表的 DVD bean 中的所有数据。但是,我们并不调用所有的五个取值方法,而是设置应用程序,只调用一个方法: getInfo() 。这大大减少了我们的 RMI 通信。

bean 的实现类在“幕后”调用所有相同的取值方法。但是,因为它们在 EJB 容器中发生,所以它们是本地调用。但是,所有数据仍将传到 bean 客户机,因此仍可以使用这些数据。如果需要对数据进行任何修改,我们可以仅用 setInfo() 方法将它们传回 bean,而不是使用四个或五个开销很大的 RMI 调用。

这种方法唯一的缺点是:有获得旧数据的轻微的风险。如果在内存中将值对象保持一段时间,您就会冒这种风险。虽然值对象包含数据库中数据的快照,但它不能动态地反映数据的更改。避免旧数据的最佳方法是立即使用值对象;如果稍后您需要再次使用它,则应该花一次 RMI 开销来再次调用 getInfo() ,以确保可以使用最新数据。

在您的 EJB 应用程序中使用值对象可以产生极大的性能优势,在具有多个取值方法的 bean 中尤其是如此。我的下一篇技巧文章将以和本文相似的风格,着重讨论在结合 EJB 组件使用 JNDI 时减少性能开销。到那时,我将在网上与您见面。



参考资料

  • 您可以参阅本文在 developerWorks 全球站点上的 英文原文.

  • 对于一切与 EJB 技术相关的事情,Sun Microsystems 的 EJB 主页是很好的参考资料。


  • The Server Side提供了许多关于 J2EE 的文章和信息。


  • 教程 EJB fundamentalsdeveloperWorks)提供了对 Enterprise JavaBeans 技术的全面介绍,并特别关注了 EJB 组件在分布式计算环境中所起的作用、体系结构、扩展 API 以及使用 EJB 技术的基础。


  • 访问 developerWorks Java 教程页面以获得其它免费的 Java 技术相关的教程清单。


  • 您可以在 developerWorks Java 技术专区找到关于 Java 编程的各个方面的数百篇文章。


关于作者

Brett McLaughlin 的照片

Brett McLaughlin 是当今企业编程领域的主要权威之一。他在 Nextel Communications 和 Allegiance Telecom, Inc. 设计、规划和实现过企业解决方案,并协助开发了 Lutris Enhydra 开放源码 J2EE 应用程序服务器。他编写过关于 XML、Java、数据绑定和企业应用程序的书籍,并撰写过 50 多篇关于企业编程的文章。此外,Brett 还是现今可用的每种开放源码 J2EE 应用程序服务器(JBoss、Enhydra 和 OpenEJB)的负责成员。他还是用于 Java 和 XML 的 JDOM API 和 Apache Turbine 项目的共同创始人,并参与了许多其它开放源码项目。他目前为 O'Reilly & Associates 撰写和编辑文章,该公司是全球主要的技术出版商。可通过 brett@oreilly.com 与 Brett 联系。




对本文的评价

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

建议?




回页首


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