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

来源:互联网 发布:肺 三维重建 软件 编辑:程序博客网 时间:2024/06/06 06:56

简单实体 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 时减少性能开销。到那时,我将在网上与您见面。