新的 EJB 2.0 规范不仅仅是一个新的阶段性发行版,它加入了许多引人注目的变动,包括 CMP 组件模型中的一些变动和一种新的 bean 类型,它们将增强您在开发应用程序时的灵活性和可移植性。请率先了解此新规范的功能,本月已发布了它的公开草案。
2000年6月2日发布的 Enterprise JavaBeans 2.0 不仅是一个阶段性发行版,而且是该规范的一个新版本。整个规范有 500 多页,比以前的 EJB 1.1 规范长了 200 页 (66%)。该规范中最重要的变动是对容器治理的持久性 (CMP) 所作的更改,以及引入了一种全新的 bean 类型,即 MessageDrivenBean。
EJB 2.0 中的大量更改都集中在一种新 CMP 组件模型的定义中。它完全不同于旧的 CMP 模型,因为它引入了一个全新的成员,即持久性治理器,并引入了全新的方式来定义容器治理的字段,以及定义这些字段与其它 bean 和从属对象的关系。
MessageDrivenBean (消息 bean)的引入也是非常重要的。消息 bean 体现出 JMS (Java Message Service)与 EJB 相集成,以创建出一种全新的 bean 类型,它设计用来处理异步的 JMS 消息。这种振奋人心的新型 bean 为 JMS 客户机提供一种组件模型,答应将它们部署到 EJB 容器系统的丰富而强健的环境中去。
对该规范还作了许多较小的其它更改。这些其它更改虽然也重要,但它们主要是涉及使该规范更严格,以便消除多义性,并使这些组件具有更高的可移植性。本文集中讨论 EJB 2.0 中引入的新 CMP 和消息 bean 组件模型。
我将提供几个具体的例子,所以读者应该很轻易跟上并理解它。但是,EJB 初学者可能发现这个材料比较困难,因为它假定读者已对 EJB 有了基本的了解。有关 EJB 的具体信息,请参阅参考资料。
容器治理的持久性
容器治理的持久性在 EJB 2.0 中发生了根本变化。在 EJB 2.0 中,持久性治理器在运行时自动处理 CMP 实体 bean 的持久性。持久性治理器负责根据一种称为抽象持久性方案的新的 bean 持久性治理器合约,将实体 bean 映射到数据库。此外,持久性治理器还负责实现和执行多种查找方法,这些查找方法均基于一种称为 EJB QL 的新型查询语言。
注重到以下事实是很重要的,即符合 EJB 2.0 规范的产品必须能支持 EJB 1.1 CMP 模型,又能支持新的 EJB 2.0 模型。虽然这两种模型并不兼容,但是为了保证向后兼容性,就必须能支持 EJB 1.1 模型。
抽象持久性方案
为了理解抽象持久性方案是如何工作的,以及它为什么重要,我将为您快速地回顾一下在 EJB 1.1 中是如何处理 CMP 的,随后再讨论在 EJB 2.0 中如何定义它。
EJB 1.1 中的 CMP 模型
在 EJB 1.1 中,bean 开发人员负责将 bean 类的持久性字段声明为 Java 基本类型或可序列化类型。下列示例显示了一个 Employee 企业级 bean 类,它是按 EJB 1.1 定义的,带有几个 CMP 字段:
// Employee bean 类
public class EmployeeBean implements
java.ejb.EntityBean {
// 实例字段
EntityContext ejbContext;
file:// 容器治理的字段
public int identity;
public String firstName;
public String lastName;
public double salary;
public Address address;
public Integer ejbCreate(int id, String fname,String lname){
identity = id;
firstName = fname;
lastName = lname;
return null;
}
...
// Address 从属类
public class Address implements Serializable{
public String street;
public String city;
public String state;
public String zip;
}
当将关系数据库用于持久性时,基本字段如 identity、firstName、lastName 和 salary,很轻易持久化,因为它们很好地映射为 SQL 类型,如 INTEGER、CHAR 和 DOUBLE。
在 EJB 1.1 中,CMP bean 的 XML 部署描述符提供 cmp-field 元素,用以标识此 bean 类中的持久性字段(容器治理的字段)。如下所示,cmp-field 元素用来区分写入数据库的字段和不写入数据库的字段。例如,ejbContext 字段就不包括在容器治理的字段的列表中,因此它不是持久性字段。
EmployeeEJB
...
Container
...
identity
firstName
lastName
salary
address
...
容器提供者提供一种工具,用来将 bean 的持久性字段映射到数据库表中的列,通常每个 bean 对应一个表。但是,可序列化的类型,如 Address,就比较难于持久化。在 EJB 1.1 中,没有标准的方法将可序列化的对象映射到关系数据库。虽然 Address 类有其自身的字段集,但 XML 部署描述符并没有提供一种机制,来将这些字段映射到数据库。在大多数情况下,人们期望将可序列化的对象(如 Address)作为二进制类型(有时称为 blob 类型)持久化到某个数据库表中。
由于实体 bean 的数据方案逐渐复杂起来,所以这个问题也变得严重了。例如,Employee bean 可能有多个类似于 Address 的子对象,如 Benefits 和 JobPosition。这些子对象称为从属对象,可以形成关系数据库中跨几个表的复杂对象图。另外,EJB 1.1 中的 CMP 在很大程度上不足以持久化与其它 bean 的关系。在 EJB 1.1 中,假如某个 bean 预备维持与另一个 bean 的关系,则容器会自动将主要害字或句柄用作一个链接。与某些其它 bean 的关系其性质可能是双向的,或者要依靠于一些不易用主要害字或句柄来表示的字段,为了保持与这类 bean 的关系,上面的办法已被证实是一种远未完善的机制。
EJB 2.0 的 CMP 模型
在 EJB 2.0 中,CMP 实体 bean 和持久性治理器之间的新合约,使您能够在实体 bean 中定义更复杂的、可移植性更强的关系,包括 bean 与 bean 之间、bean 与从属对象之间、甚至从属对象与从属对象之间的关系。
持久性治理器是新加入到 Enterprise JavaBeans 部署过程中的。容器厂商,或专长于特定数据库的持久性的厂商,将能提供这种持久性治理器。其思路是将用于治理 bean 关系的机制从容器中分离出来,容器只负责治理安全、事务和资源。这种职责上的分离使不同的持久性治理器能够与不同的容器一起工作。它也使实体 bean 在不同 EJB 厂商之间以及在各种持久性治理器之间具有更强的可移植性。
假如您使用或学习过 Thought Inc. 生产的,能自动为 EJB 1.1 容器生成 BMP(bean 治理的持久性)bean 的产品 CocoBase,则您对持久性治理器工具如何工作就已经比较熟悉了。CocoBase 根据 bean 部署者提供的,从对象到关系的映射信息,为 BMP bean 生成全部数据库访问逻辑。在 EJB 2.0 中,持久性治理器能够根据部署描述符、bean 的抽象持久性方案和部署者完成的工作所提供的信息,生成 CMP 实体到关系数据库的映射。但是,持久性治理器并不局限于关系数据库。也可以为对象数据库以及遗留的系统和 ERP 系统(如 SAP)开发持久性治理器。
为了将持久性治理器从容器中分离出来,必须定义 bean 与持久性治理器之间的合约。这个合约在新的抽象持久性方案中表现出来。此方案是通过部署描述符中一组新的 XML 元素和 CMP 实体 bean 中的一组代码习语定义的。在 EJB 2.0 中,CMP bean 类被声明为抽象类,它的持久性字段和关系字段是使用抽象的读方法和写方法来访问的,而这两种方法的方法特征则映射为 XML 部署描述符中的特定元素。
在部署该 bean 时,您将使用持久性治理器工具,根据 XML 部署描述符和 bean 类,来具体实现此抽象 bean 类及其从属对象类。具体实现将包括数据访问代码,此代码将在运行时将 bean 的状态实际读出和写到数据库中。在运行时,容器使用由持久性治理器工具生成的子类,而不使用 bean 提供者定义的抽象类。
bean 类的继续层次结构
为了使讨论更充实,这里提供一个 CMP 实体的示例,它更具体地说明了抽象持久性方案是如何工作的。
EJB 2.0 中的一个示例 CMP 实体
在 EJB 2.0 中,容器治理的实体 bean 被定义为抽象的,而且它的持久性字段并不在 bean 类中直接定义。作为替代,开发了一种抽象的持久性方案,从而答应 bean 提供者间接地声明持久性字段和 bean 关系。下面是 Employee bean 的一个示例,它使用了新的