[转载]WebSphere 4.0 中的 EJB 元数据: 第 1 部分:四个文件的故事

WebSphere 4.0 中的 EJB 元数据: 第 1 部分:四个文件的故事


这篇文章说明了 WebSphere 如何使用元数据将容器管理的持久性(CMp)EJB 映射到数据库表。通过使用大量的代码示例和几个简单的技巧,它显示了您怎样才能更好地利用 WebSphere 工具以及如何处理涉及到 CMp 的自动配置和部署问题。

©2001 International Business Machines Corporation. All rights reserved.

介绍

J2EE 1.2 和 EJB 1.1 规范对企业级 Java™ 开发者来说是一个很大的进步。它们提出了企业应用程序缺少的一个概念 ? 通过一种简单的、易于理解的格式(这种格式本质上是纯文本格式)来读写 J2EE 应用程序的元数据。IBM 在 WebSphere® ApplicationServer,版本 4.0中已经以这种思想为基础做了很多工作。我们在本文中将会看到,开发人员在使用 WebSphere 4.0 和 WebSphere Studio Application Developer 时在这一理念上是有多种选择的。




回页首


什么是元数据?

元 数据的字面意思是“关于数据的数据” ? 它是应用程序的一些部分,不是代码,但描述代码,并描述这些代码如何适合其它代码。元数据是关于资源(比如 EJB 或 servlet)以及这些资源如何被其它 J2EE 资源使用的信息。元数据的一个示例是EJB 1.1 部署描述符,[EJB 1.1] 中有对它的描述。

让我们假定您正在构建一个要部署到 WebSphere 4.0 的简单 EJB .jar 文件。 .jar 文件包含一个单独的容器管理持久性(CMp)的实体 bean,这个实体 bean 表示一个人。下面的部署描述符(名为 ejb-jar.xml )包含在我们的 EJB .jar 文件的 META-INF 目录中,描述了我们的 person EJB:

JavaBeans 1.1//EN" "http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd">



personEJB
com.ibm.demo.ejbs.personHome
com.ibm.demo.ejbs.person
com.ibm.demo.ejbs.personBean
Container
java.lang.Integer
False
id
name
age
educationLevel
id





Everyone can gain access to this EJB.

everyone


everyone

personEJB
*




personEJB
*

Required




这 个简单的部署描述符定义了这个 EJB 的几部分 ? 比如 home 接口、远程接口、bean 类和 CMp 字段(将由容器管理的 bean 类中的字段)。换句话说,它们将由部署期间生成的代码将其存储在关系数据库中并从关系数据库中检索它们。最后,部署描述符包含其它信息,比如为这个 bean 定义的容器事务设置以及 EJB 安全性角色。

WebSphere 将这些信息用于多种用途 ? 例如,确定如何处理事务(是为每个方法启动一个新事务还是让现有的事务“流过”每个 EJB 方法)。这些信息还被 WebSphere 安全性系统用于确定一个用户(被 WebSphere 映射到一个或多个 J2EE 角色的人)是否可以访问一个特殊的 EJB 方法。但我们感兴趣的部分是,WebSphere 还使用元数据确定如何生成将实际执行向关系数据库存储和从关系数据库检索信息工作的 CMp 持久性代码。

目前为止,这就好像可以在其它书籍和文章中找到百万个其它部署描述符示例一样,我怀疑你们中 的大多数是否已经了解了一些新知识。(如果是,您可能希望在继续往下看之前重温一下 EJB 1.1 规范。)我将不再重复谈论各个标记在部署描述符中的意义。而是让我们来了解一下 WebSphere 使用其它哪些元数据与 EJB 关联,以及您如何在自己的工程中使用这些元数据。




回页首


WebSphere 4.0 中的元数据

让我们开始先检查一下当使用 WebSphere 应用程序装配工具(WebSphere Application Assembly Tool,AAT)为这个 EJB 生成部署代码时将会发生什么事。记住:有两种形式的 EJB JAR:

“未部署”形式 只包含远程和 home 接口、bean 实现类以及部署描述符。 “已部署”形式 包含支持持久性、事务和分发所必需的类以及部署期间由应用程序服务器生成的类。

在 本文中我将不讨论在 WebSphere 中如何完成部署,因为在产品文档和 [Brown 2001] 中已对它进行过很好的描述。这里我们想做的是研究 WebSphere 在这个部署过程中使用的信息。WebSphere 高级版(WebSphere AE)支持三种将 CMp EJB 映射到数据库的方法:

自顶向下 EJB 中的信息被用于创建与 CMp EJB 的受管字段相对应的数据库表。 中间相遇 在 CMp EJB 的受管字段和一张或多张数据库表的列之间有一个预先指定的对应关系。 自底向上 为数据库表中的列创建 EJB 字段。

这 里关键的一点是 WebSphere 需要 EJB 部署描述符之外的额外元数据来执行这些映射。元数据被用于推动一个类的代码生成过程 - 该类实际执行特定的 SQL 语句,然后执行将数据库表外的信息复制到 EJB 以及与此相反的过程。如果您能理解为自顶向下映射生成的元数据,那么您就很容易理解如何使用 WebSphere,通过中间相遇或者自底向上的方法将 CMp EJB 映射到数据库表。

我们继续来看这个示例。如果您使用 WebSphere AAT 为 EJB JAR 文件生成部署代码,或者不指定关于数据库映射的任何额外信息,使用 WebSphere 管理控制台( WebSphereAdministration Console)部署一个未部署的 EJB JAR 文件,它将执行自顶向下的映射。所以,如果您在 AAT 中打开包含这个描述符(附加的)的 JAR 文件,生成部署代码,然后将 JAR 展开到一个目录,您将看到 META-INF 目录现在包含下列文件:

/META-INF
ejb-jar.xml
MANIFEST.MF
Map.mapxmi
Table.ddl
/Schema/schema.dbxmi

这些文件中的其中一个是我们期待的 ? MANIFEST 文件,任何 JAR 文件中都有这一部分,所以我们不会特别关注它。其它文件比较有趣:

  • EJB-JAR.xml
    与上面那个一样,但 AAT 把它修改为包含额外的识别标记。
  • /Schema/schema.dbxm
    包含数据库模式和 CMp EJB 所映射的表的 XML 表示。
  • Map.mapxmi
    包含 XML ? 该 XML 展示 EJB-JAR.xml 文件中的 CMp 字段如何映射到模式文件中的数据库模式。
  • Table.ddl
    包含创建模式文件中所描述的表必需的 SQL。

让我们开始先看一下 EJB-JAR.xml 文件中发生了什么变化。下面的文件部分显示了发生的变化:




personEJB
com.ibm.demo.ejbs.personHome
com.ibm.demo.ejbs.person
com.ibm.demo.ejbs.personBean
Container
java.lang.Integer
False

id


name


age


educationLevel

id


_


您可以看到,已经添加了几个东西。AAT 已经向下列标记添加了一个 id 属性:

  • Ejb-jar
  • Entity
  • Cmp-field

这些 id 标记唯一地识别 JAR 中包含的每个实体 EJB 中的每个 CMp 字段。我们立刻就会看到,这个唯一的标识对于 WebSphere 正确操作其它元数据文件来说至关重要。

下一个变得比较熟悉的文件并不是一个真正的元数据文件,而是 WebSphere 为方便您而生成的一个文件。这是个 Table.ddl 文件,它包含创建自顶向下映射表的 SQL:

CREATE TABLE pERSONEJB
(ID INTEGER NOT NulL,
NAME VARCHAR(250),
AGE INTEGER,
EDUCATIONLEVEL INTEGER);
ALTER TABLE pERSONEJB
ADD CONSTRAINT pERSONEJBpK pRIMARY KEY (ID);

如果您把这个文件与上面的 EJB 部署描述符仔细比较,您会看到与这个 EJB 相对应的表的名称与部署描述符中的 标记中指定的名称相同,而且该表的列与上面 标记中的名称相匹配。最后,与 标记的值相对应的列已经被声明为NOT NulL(因为它将是这张表的键),而且还为这个列添加了主键约束。

您 可能想知道 WebSphere 怎样知道使用什么数据类型来创建这个表。答案很简单 ? 有一个固定映射,它将数据库中的数据类型和容器管理属性(EJB Bean 类代码中定义的)的 Java 语言类型相映射。这个映射因数据库而异,这就是在把 EJB 部署到 WebSphere 时您必须在 AAT 或 WebSphere 管理控制台中选择数据库类型的原因。

既然您已经看过了 Table.ddl 文件并理解了WebSphere 如何从 CMp EJB 的代码和 EJB 部署描述符中的元数据获取它,下一个要浏览的文件就是 schema.dbxmi 文件,该文件保存在 META-INF 目录的 Schema 子目录中。

xmlns:RDBSchema="RDBSchema.xmi">
tableGroup="RDBTable_1">


primaryKey="SQLReference_1" database="RDBDatabase_1">
group="SQLReference_1">
xmi:id="SQLExactNumeric_1">
href="UDBV7_primitives.xmi#SQLExactNumeric_1"/>



xmi:id="SQLCharacterStringType_1" length="250">
href="JavatoDB2UDBNT_V71TypeMaps.xmi#SQLCharacterStringType_250"/>



xmi:id="SQLExactNumeric_2">
href="UDBV7_primitives.xmi#SQLExactNumeric_1"/>



xmi:id="SQLExactNumeric_3"> href="UDBV7_primitives.xmi#SQLExactNumeric_1"/>


xmi:id="SQLReference_1"
name="pERSONEJBpK" members="RDBColumn_1" table="RDBTable_1"
constraint="Constraint_pERSONEJBpK"/>
type="pRIMARYKEY" primaryKey="SQLReference_1"/>



这个文件比我们看过的其它文件更复杂,因为它使用被称为 XMI的 XML 标准,这个标准用 XML 表示对象设计和对象模型的信息。实际上,它描述的是 WebSphere 表示这个 EJB 的数据库模式的内部方法。它不希望像 EJB 部署描述符那样容易读。然而,只要您学习几分钟,要理解它也不那么困难。紧接着描述这个文件所使用的版本和名称空间的 XMI 开始标记后,您会看到下列标记:

tableGroup="RDBTable_1">



关于这组标记的唯一重要的事情是它指定这个特定的模式使用 DB2® UDB 7 映射将 Java 类型映射到数据库类型。

下一段更有趣。注意,这些标记具有下面的结构,如下图 1 所示。


图 1. 数据库标记结构
数据库标记结构

您可以看到,有一个 标记与上面 CREATE TABLE SQL 中定义的表相对应。同时表中定义的每个列都有一些对应的 标记。最后,每个 标记包含描述原始类型和列类型的类型信息。原始类型(originating type)提供关于基本数据库类型(数字类型等)的信息,而类型标记显示如何扩展这个特定列的原始类型(通过提供长度、范围或者精度信息)。

这里我们有表的一个 XML 定义。乍看起来,它好象没什么用,因为它与 Table.ddl 文件中的信息非常相似。但是,下一个文件,也即 map.mapxmi 文件,将各种东西都集中在一起,使得这些都有了意义:

xmlns:xmi="http://www.omg.org/XMI"
xmlns:ejbrdbmapping="ejbrdbmapping.xmi" xmlns:ejb="ejb.xmi"
xmlns:RDBSchema="RDBSchema.xmi" xmlns:Mapping="Mapping.xmi"
xmi:id="EjbRdbDocumentRoot_1" outputReadOnly="false" topToBottom="true">
xmi:id="RdbSchemaproperies_1" primitivesDocument="DB2UDBNT_V71">
href="RdbVendorConfigurations.xmi#DB2UDBNT_V71_Config"/>


href="META-INF/Schema/Schema.dbxmi#RDBDatabase_1"/>

xmi:id="primaryTableStrategy_1">


href="META-INF/ejb-jar.xml#ContainerManagedEntity_1"/>
href="META-INF/Schema/Schema.dbxmi#RDBTable_1"/>

href="META-INF/ejb-jar.xml#CMpAttribute_1"/>
href="META-INF/Schema/Schema.dbxmi#RDBColumn_1"/>
href="JavatoDB2UDBNT_V71TypeMaps.xmi#Integer-INTEGER"/>


href="META-INF/ejb-jar.xml#CMpAttribute_2"/>
href="META-INF/Schema/Schema.dbxmi#RDBColumn_2"/>
href="JavatoDB2UDBNT_V71TypeMaps.xmi#String-VARCHAR"/>


href="META-INF/ejb-jar.xml#CMpAttribute_3"/>
href="META-INF/Schema/Schema.dbxmi#RDBColumn_3"/>
href="JavatoDB2UDBNT_V71TypeMaps.xmi#int-INTEGER"/>


href="META-INF/ejb-jar.xml#CMpAttribute_4"/>
href="META-INF/Schema/Schema.dbxmi#RDBColumn_4"/>
href="JavatoDB2UDBNT_V71TypeMaps.xmi#int-INTEGER"/>


href="JavatoDB2UDBNT_V71TypeMaps.xmi#Java_to_DB2UDBNT_V71_TypeMaps"/>


要 在这篇短小的介绍性文章中全面解释这个文件,就要讲很多,但对于理解 WebSphere EJB 到 RDB 的映射工作,有几点很关键: 我的目的并不是告诉您如何从头生成这个文件,而是想说明它做什么工作,这样您就能够对这个文件(和其它我们已讨论过的文件)做一些小的更改来应对使用 WebSphere 进行 CMp 映射过程中的简单问题。

让我们从文件中下面几行代码开始:

  href="META-INF/ejb-jar.xml#ContainerManagedEntity_1"/>
href="META-INF/Schema/Schema.dbxmi#RDBTable_1"/>

这里,我们得到了第一个暗示:正在发生什么事情。您可以看到,这两行代码将 ejb-jar.xml 文件中的一个特定的 EJB 引用(ContainerManagedEntity_1,它是我们先前看到的“personEJB”的标识)和模式中定义的一张特定的数据库表 (RDBTable_1,它是我们先前在模式文件中看到的 pERSONEJB 表)链接在一起。实际上,如果这是个多表映射(一些列来自两个或多个表的映射),您会看到多个 标记,每个标记都引用一个不同的模式文件和文件 1 中的表。这个原则同样适用于其余的文件,如下一部分指出的那样:


href="META-INF/ejb-jar.xml#CMpAttribute_1"/>
href="META-INF/Schema/Schema.dbxmi#RDBColumn_1"/>



在这个代码段中,您看到了 ejb-jar.xml 文件中定义的、特定的容器管理字段(CMpAttribute_1 是字段标识)与模式中定义的、特定的数据库列(RDBColumn_1 是 ID 列)之间的连接。定义了输入和输出映射后,困惑我们的最后一点是类型映射 ? 您可以看到,它将 Java 类型(Integer)映射到关系数据库类型(INTEGER)。EJB 中的所有 CMp 字段都会重复这类映射。

如果您熟悉 VisualAge® for JavaEJB Support 中的转换器,知道使用 标记选择缺省的转换器就可以了。如果您需要一个与指定转换不同的转换(假设一个知道如何将特定的字符串“Yes”和“No”转换为布尔值的专门的转换器),您可以在这里通过 标记指定它。

下图 2 显示了这三个主要的 XML 文件与它们的成分部件之间的交互。


图 2. 元数据文件关系
元数据文件关系



回页首


简单的元数据技巧

既然您了解了这些 XML 文件的存在、结构和相互关系,问题是,您要用它们来做什么呢?首先,让我们来阐明您 应 该用它来做什么。您不应该为了执行自己的自底向上或复杂的中间相遇映射而试图创建这些文件。原因是由于这些文件本意是让 WebSphere 工具集 ? VisualAge for Java 4.0,特别是 WebSphere Studio Application Developer 2 ? 来生成和编辑,所以没有在 WebSphere 文档中充分说明底层模式。实际上,Application Developer 文档包含这些文件使用的 XMI 对象模型的内部表示的最好描述。如果您是一个工具构建者,想用这些信息生成自己的实体 EJB ,那么请考虑使用文档中有的 Application Developer 工具 ApI 来构建这些文件,而不要试图从 XML 反向设计一个对象模型。

另一方面,还有一些例子,在这些例子中,直接更改 XML 可以作为更新 EJB 的最容易的方法。例如,许多企业环境建立了不同的数据库表来支持开发、测试和生产。在某些情况下,这些数据库可能在 DB2 或 Oracle 的相同实例上被托管,它们只是模式名不同(可能是 DEV.pERSONEJB、TEST.pERSONEJB 和 pROD.pERSONEJB)。您将怎样写自己的代码使其完全不依赖于环境?对于 CMp 实体 EJB,WebSphere 使这项工作变得很简单。您只需在模式标记中更改模式名称,然后将 EJB JAR 文件部署到用于三种环境的不同 WebSphere 实例。例如,对于 DEV,您的标记可能看起来是这样的:

name="DEV" tableGroup="RDBTable_1">

而对于 pROD,您的标记可能看起来是这样的:

name="pROD" tableGroup="RDBTable_1">

关 于这个简单的替代方法的很不错的一点是您可以使用工具(如 AWK、SED 或者甚至 ANT)使其自动化,这些工具也可以用于调用适当的 WebSphere 命令行工具( 高级单服务器版上的 SEAppInstall 或高级版上的 WSCp)来生成部署代码和安装结果应用程序。

在这种情况下,您将从一个未部署的 EJB JAR 文件开始,将它一次部署好,然后将上面描述的元数据文件复制回您的工程的构建树,这样它们就变成了未部署 JAR 文件的一部分。当您部署 JAR 时,WebSphere 适当地选择一些元数据文件并生成部署代码。

您可以执行的另一个简单更改是当 EJB 定义或数据库模式发生更改时更新 XML 来执行最小的中间相遇映射。例如,假设您后来决定在工程中将 educationLevel CMp 字段的名称更改为 edLevel。您只需更新 ejb-jar.xml 文件来更改字段,如下所示:


edLevel>/field-name>


请保持 id 不变,因为(就象我们先前看到的)这个id 实际上是用于将 CMp 字段映射到模式中相应的列。您可以想象得到,数据库中相应的更改将保持 ejb-jar.xml 不变,同时适当地更新 schema.dbxmi 文件。再次说明,不管在哪种情况下,编辑过 XML 后都要重新部署 EJB jar 文件。




回页首


总结

本 文已经研究了在 WebSphere 4.0 和 Application Developer 中映射到关系数据库的 CMp EJB 的一些隐藏的部分。它稍微描述了一下 ejb-jar、模式和映射文件如何进行互操作,以及操作这些文件的工具如何发挥作用。这些信息有助于您更好地使用用于 CMp 的 WebSphere 工具,并有助于规划出用来处理涉及到 CMp 的自动配置和部署问题的最好方法。本文的 第 2 部分将研究这些文件的其它一些功能,比如关联、继承、转换器和编写器,还要研究 ejb-jar 扩展文件,这种扩展文件在 CMp EJB 的定制查找程序方法中被使用。