利用Geronimo深入EJBWeb应用程序

深入了解功能强大的 Geronimo 应用服务器的内部工作,学习如何使用它来开 发数据库应用程序。Java 开发人员 Neal Sanche 用文章“将数据库连接到 Geronimo 应用服务器的三种方法”(developerWorks,2005 年 6 月)开始了这 趟旅行,这篇文章指导您创建简单的电话簿数据库应用程序。在本文中,您将学 习如何扩展初始数据库应用程序,并为之提供一个使用 Apache Struts 和 Enterprise JavaBeans (EJB) 后端构建的功能用户接口。您还将学习如何使用 Apache Maven 构建系统来构建、打包和部署电话簿数据库应用程序。通过本文学 习如何简化您的企业 Web 应用程序开发过程。

技术概览

在学习示例应用程序之前,首先要详细了解一下将用于创建和部署该应用程序 的三种技术。(要阅读有关其中每一种技术的详细信息,请参阅 参考资料。)

Maven 是用于构建 Java 应用程序的应用程序,它从源代码一直构建到打包至 Web 站点。Geronimo 应用服务器是使用 Maven 应用程序的构建系统构建的。在 它的核心内,Maven 的可扩展框架允许创建模块以执行构建软件组件时需要的一 些动作。谈到 Apache Ant(Java 构建工具),Maven 的动作已经与使用 UNIX 命令 make 生成的结果进行了比较。Maven 脚本还允许将应用程序自动部署到正 在运行的 Geronimo 服务器中。本文展示了如何使用 Maven 来将源代码打包到完 整的 Java 2 Platform, Enterprise Edition (J2EE) 企业应用程序中。

Struts 是基于 Model 2 架构的 Web 应用程序框架(参阅 参考资料 获得 JSP Model 2 的完整描述)。该混合架构最大程度地将业务逻辑和显示逻辑隔离 。Struts 通过将业务逻辑隔离到纯 Java 类中来实现这一目标,纯 Java 类操作 数据,并提供了丰富的标记库,该库可用于在编写 JavaServer Pages (JSP) 时 显示数据。(在无数可用的 Web 开发框架中,许多框架都有很高的人气,比如 Tapestry 和 JavaServer Faces,而 Struts 一直是我偏爱的一个。)

XDoclet 起源于存在已久的 Java 文档工具 Javadoc。XDoclet 开发人员最初 以一种新颖的方法使用 Javadoc,即使用专门的注释来生成可以被编译成源代码 的模型。他们从 Javadoc 的实际使用抽身而出,生产出他们自己的变种,叫做 Xjavadoc。但是在 XDoclet 早期,仍然需要在源代码的 Javadoc 注释中使用标 记来自动生产自动生成的代码。编写 J2EE 应用程序中的源代码和部署描述符文 件可能十分冗长乏味。对于每一百行左右的 Java 代码,预计可以生成至少三倍 多的支持 J2EE 描述符代码来完成工作。为了大大减少开发多层企业应用程序的 痛苦,XDoclet 伸出援手,提供了代码标记和代码生成以使大部分部署描述符自 动生成。这样就隐藏了 J2EE 的大量复杂性,但您要清楚代码生成器在构建什么 ,因为当事情没有如期进行时,您必须检查它。

部署计划

正如在简介中提到的,Maven 被 Geronimo 团队用来构建整个应用服务器。您 可以利用 Maven 构建工具的强大功能来编译应用程序源代码,执行代码生成(需 要 XDoclet 的帮助),绑定企业应用程序模块,并最终将其部署到正在运行的 Geronimo 服务器中。

该过程以三个文件开始。第一个文件 project.xml 定义什么是所谓的项目对 象模型(Project Object Model,POM)。它列出应用程序的相关信息,包括应用 程序名称、编写者、版本号、对构建应用程序非常重要的依赖关系,以及对如何 构建应用程序的概述。出于本文目的,我们将主要研究 POM 的依赖关系部分。( 参考资料 中有到整个 POM 文件的链接。)

Maven 使用 project.xml 的依赖关系部分从 Internet 上的指定资源库中下 载构建应用程序所需的工件。iBiblio(参阅 参考资料)就是这样一个资源库, 它包含数百个开放源代码 Java 库和支持文件,以及这些库的 POM 信息。它收集 了大量信息,目的只有一个,即简化应用程序构建过程中 Java 开发人员的生活 。电话簿应用程序 project.xml 文件的依赖关系部分由 23 个依赖关系组成,其 中一半是 .jar 文件,用于支持 Struts 和 DisplayTag 标记库。其余的依赖关 系主要是 XDoclet 要求。不使用 Maven,每个依赖关系都需要与示例应用程序绑 定在一起。

Maven 只在第一次编译应用程序时下载所有依赖的工件。以后的编译运行利用 Maven 的本地资源库(已下载工件的本地高速缓存,通常位于 $HOME 目录的 .maven 目录下)来获得工件。

安装 Maven 1.0.2

我们的示例应用程序需要对 Maven 进行一些初始设置以使一切正确工作。首 先,需要安装 Maven 1.0.2(参阅 参考资料 中的 Maven Web 站点链接)。安装 完成后,在命令行输入 maven,将看到类似如下的信息:

E:/Documents and Settings/Neal/My Documents/eclipse/workspace/Phonebook> maven__ __| // |__ _Apache__ ___| |//| / _` / V / -_) ' / ~ intelligent projects ~|_| |_/__,_|/_//___|_||_| v. 1.0.2

编译 Geronimo

然后,按照 Wiki(参阅 参考资料)上的指令从源代码编译 Geronimo。成功 构建之后,Geronimo 工件将位于本地资源库。它们是构建示例应用程序所必需的 。编译完 Geronimo 之后,查找 geronimo-deployment-plugin-1.0- SNAPSHOT.jar 文件,并将其安装到 $MAVEN_HOME/plugins 目录中,否则可能会 看到如下消息:

Tag library requested that is not present: 'geronimo:deploy' in plugin: 'null'

安装 XDoclet 1.2.3

最后,需要将 XDoclet 1.2.3 安装到 Maven 资源库中。如果试图构建示例应 用程序,会显示一条 Maven 消息,指明它无法找到一些其他的 XDoclet 1.2.3 工件,这时您可能需要下载 XDoclet 1.2.3(lib 包),并将 .jar 文件解压到 位于 .maven/reposiTory/xdoclet/jars 的本地 Maven 资源库中(参阅 参考资 料 以访问 XDoclet Web 站点)。如果您是 Windows 用户,应该在C:/Documents and Settings/username目录下查找该 Maven 目录。如果您是 UNIX 用户,应该 在主目录下查找该目录。还应该通过将 maven-xdoclet-plugin-1.2.3.jar 添加 到 $MAVEN_HOME/plugins 目录来安装 XDoclet Maven 插件。

成功构建

具备这些先决条件之后,构建过程应该能够顺利进行。当然,可以在进行上述 工作之前尝试构建,查看 Maven 找不到哪些文件,然后只安装这些文件。可以尝 试在示例应用程序的顶层目录中运行 Maven。首先,许多工件将被下载,最后, 您将看到 BUILD SUCCESSFUL 消息。

要更多了解 Maven 做什么,研究一下 maven.xml 和 project.properties 文 件。Maven 是面向目标的。它读取 maven.xml 并尝试满足顶层项目元素的默认属 性中指定的所有目标。在本例中,它尝试满足部署目标指明为先决条件的所有事 项;也就是说,它将尝试构建 .ear 文件,然后尝试停止和启动应用程序。应用 程序的部署是通过上述的 Geronimo Deployment Maven 插件执行的。当然, Geronimo 服务器应该运行 —— 否则构建将失败,并显示如下消息:

Failed to retrieve RMIServer stub: javax.naming.ServiceUnavailableException[Root exception is java.rmi.ConnectException: Connection refused tohost: 10.0.0.7; nested exception is:     java.net.ConnectException: Connection refused: connect]

如果收到该消息,使用如下命令启动 Geronimo 服务器:

E:/geronimo-snapshot>java -jar bin/server.jar org/apache/geronimo/DebugConsole org/apache/geronimo/RuntimeDeployer

该命令告诉 Geronimo 启动其服务器、DebugConsole 应用程序配置和 RuntimeDeployer 配置。

调试控制台

DebugConsole(参见 图 1)是可选组件,允许通过一个小 Web 应用程序(参 阅 http://localhost:8080/debug-tool)查看 Geronimo 服务器中在运行什么。

图 1. Geronimo DebugConsole

示例顶层页面

构建完示例应用程序之后,可以访问它的顶层页面,您将看到如 图 2 所示的 内容。

图 2. 使用 Struts 1.2.7 构建的 Geronimo Phonebook 示例应用程序

完成应用程序构建之后:底层内容

既然已经成功构建了应用程序,而且看到了使用 Maven 的强大功能和简单性 ,现在该学习使它完全运行所必需的文件布局和部分代码。首先介绍 Web 应用程 序层,然后介绍 EJB 层。最后将查看结缔组织 —— 连接所有组件并让它完全工 作的部署计划和配置文件。参考 图 3 所示的文件目录树,以便找到这些文件。

图 3. 示例应用程序文件的目录布局

Web 应用程序层

Web 应用程序是用 JSP 和 Struts 1.2.7 框架编写的。在 src/webapp 目录 中将会找到组成示例应用程序 Web 接口的文件。

该应用程序由两个主要视图组成:电话号码列表和电话号码编辑屏幕。从数据 库中编辑简单记录必需的所有特性(添加、删除、编辑、更新和列表)都存在。 src/java/org/acme/phonebook/struts 目录包含大量 Struts 动作来执行这些必 需功能,比如创建新条目,删除条目,列出所有条目,编辑现有条目。

Struts Tiles 模板系统用于确保花费在让 Web 应用程序外观正常上的工作最 少。webapp/pages 目录中的 site-template.jsp 文件定义应用程序的外观。

接下来介绍的两个主要 JSP 是 EditPhoneNumberPage.jsp 和 ListPhoneNumbersPage.jsp。其中每个页面及其在应用程序中的功能在 清单 1 中说明。

清单 1. EditPhoneNumberPage.jsp

   



                                         

在 清单 1 中,前几行设置将在页面中处于活动状态的标记库。它们还将站点 模板的内容区域设置为内容将显示的位置。本例展示了一个简单的基于 Struts 的输入屏幕,它用一些 标记来显示资源库文件(位于 webapp/WEB-INF/classes/resources/application.properties)中的字符串。屏 幕将名称和电话号码提交给名为 SaveEntry.do 的 Struts 动作。

如果查看 清单 2 中 SaveEntry.java 源文件中的类 Javadoc 标记,将会看 到该应用程序中 XDoclet 标记的第一个示例。这些标记定义生成 Struts 部署描 述符 struts-config.xml 必需的所有属性。

清单 2. SaveEntry.java Javadoc 类标记

/*** Save an Entry** @struts.action*  name = "phoneBookEntryForm"*  path = "/pages/SaveEntry"*  scope = "request"*  input = "/pages/EditPhoneNumberPage.jsp"*  unknown = "false"*  validate = "false"* @struts.action-forward*  name = "success"*  path = "/pages/ListNumbers.do"*  redirect = "true"*/

该示例代码位于一个 nutshell 中,展示了 /pages/SaveEntry 动作从 EditPhoneNumberPage.jsp 中获取输入,并使用 phoneBookEntryForm. 将来自页 面的用户输入打包到 Java 代码中。该动作完成之后,它重定向到 /pages/ListNumbers 动作以显示号码列表。

ListNumbers 动作位于 ListNumbers.java 文件中,它使用 清单 3 中的代码 调用名为 PhoneBookSession 的 Session EJB。

清单 3. ListNumbers 动作的 execute() 方法的代码段

PhoneBookSessionLocal session =    PhoneBookSessionUtil.getLocalHome().create();// Call the methodCollection c = session.listEntries();// Put the retrieved information into the request attributes// so the page can render them.request.setAttribute("numbers", c);

在 清单 3 中,可以看到 PhoneBookSessionUtil 类的使用。它是一个 XDoclet 生成的类,用于帮助获得 PhoneBookSession 对象的主接口。创建了一 个会话,调用了它的 listEntries() 方法,该方法返回所有电话簿条目的集合。 然后请求对象中的 numbers 属性被设置为该集合。这样做的效果是将电话号码放 到指定位置,以便用于显示条目的 JSP 可以检索并写出列表,如 清单 4 所示。

清单 4. ListPhoneNumbersPage.jsp 中的 DisplayTag

                      Edit                   Delete                ...

EJB 层

该应用程序中有两个 EJB 类。第一个类使用容器管理持久性(Container- Managed Persistence,CMP)来提供对简单数据库表 PhoneBookEntryBean 的基 于对象的访问。第二个类是一个 Stateless Session bean,它提供业务逻辑。通 常需要通过无状态会话 bean 来操作 CMP bean,因为会话 bean 可被设置来提供 对数据库的事务处理,从而在发生错误时可以回滚更新。此外,在 Session bean 中执行所有 CMP 操作使得 Web 应用程序无需知道数据库访问层的任何实现细节 。所以如果用另一种技术替换该层(比如使用 Hibernate 持久层),将无需更改 Web 应用程序中的代码。

XDoclet 主要用在 EJB 层中以提供部署描述符生成。这对于减少构建此类应 用程序所需的维护工作是十分重要的。下载源代码并查看 PhoneBookEntryBean.java 和 PhoneBookSessionBean.java 的类 Javadoc 注释 ,以了解用于定义 EJB 类的大量 XDoclet 标记。

要生成无状态会话 bean 的方法,添加名为 @ejb.interface-method 的 XDoclet 标记,其视图类型属性可以为 local、remote 或 both。该属性告诉 XDoclet 在会话 bean 的本地接口、远程接口或两种接口中生成相应方法。您还 可以控制事务处理类型。参见 清单 5,它是其中一个接口方法的示例,列出电话 簿条目并返回它们的值对象表示。

清单 5. PhoneBookSessionBean.java 类的 listEntries() 方法

/*** List all of the phone book entries.* @return a collection of PhoneBookEntryValue objects.** @ejb.interface-method view-type="both"* @ejb.transaction   type="Required"*/public java.util.Collection listEntries() {  ArrayList values = new ArrayList();  try {    Collection entries = PhoneBookEntryUtil.getLocalHome ().findAll();    IteraTor i = entries.iteraTor();    while(i.hasNext()) {       PhoneBookEntryLocal entry = (PhoneBookEntryLocal)i.next ();       values.add(entry.getPhoneBookEntryValue());    }  } catch (Throwable ex) {    ex.printStackTrace();  }  return values;}

结缔组织

在我的文章“将数据库连接到 Geronimo 应用服务器的三种方法” (developerWorks,2005 年 6 月)中详细介绍了 Geronimo 的各种部署计划的 重要性。让这么小的应用程序到达功能状态是非常有挑战性的,需要在部署计划 中提供许多小选项,还有 XDoclet 标记之间的交互、标记生成的代码,以及部署 计划。但是详细介绍这些内容超出了本文的范围。示例程序有许多配置文件和部 署计划,几乎所有的这些东西都能在项目的 src/resources 子树中找到。下文简 要介绍了这些文件的相关细节,以说明需要进行哪些修改才能让将来的应用程序 工作。

ear 子目录包含企业应用程序部署描述符、application.xml 文件和 geronimo-application.xml 文件。在该应用程序中,这些文件被配置以提供应用 程序范围的 Java 数据库连接 (Java Database Connectivity, JDBC) 连接器。 阅读“将数据库连接到 Geronimo 应用服务器的三种方法”(developerWorks, 2005 年 6 月)以获得该配置的详细信息。mysql-plan.xml 和 tranql- connecTor-1.0-SNAPSHOT.rar 文件以及 application.xml 和 geronimo- application.xml 文件中的模块定义是该配置的一部分,用于使运行时部署器正 确设置 JDBC 连接器。

geronimo-application.xml 文件包含 元素,它具有名 为 configId 的属性。该元素对于 Maven 构建脚本的自动部署特性的正确运行是 十分关键的。所设置的值可用于 maven.xml 文件中任何 的 id 属性中,如 清单 6 所示。

清单 6. maven.xml 启动目标

在 清单 6 中,因为 geronimo-application.xml 文件中的 configId 属性被 设置为 org/acme/PhoneBook,所以它还必须是自动部署语句中 id 属性的值。 Geronimo 团队为此设置了一个非常好的自动部署工具。但是,如果您经常自动部 署,请确保检查您的临时目录,因为它们可能装满了旧的部署文件。

资源目录中子目录列表中的下一个目录是 ejb 目录。openejb-jar.xml 部署 描述符在 META-INF 子目录中。该文件对于数据库和实体 (CMP) bean 之间的所 有连接是必不可少的。还必须对该文件进行小修改,以确保对于您的企业 bean 存在相应的 Java 命名和目录接口 (Java Naming and DirecTory Interface, JNDI) 名称。该文件如 清单 7 所示。

清单 7. openejb-jar.xml

       MysqlDataSource                  PhoneBookEntry       java:comp/env/ejb/PhoneBookEntryLocal       phone                name         name                       phoneNumber         phone                        PhoneBookSession                 java:comp/env/ejb/PhoneBookSessionLocal              

清单 7 最重要的元素是 及其 子元素。 元素内的名称必须与 JDBC 连接器配置的名称相匹配,如下列代码段所示:

...    MysqlDataSource...

openejb-jar.xml 中的 元素也是正常工作所必需 的。如果收到找不到 JNDI 名称的错误消息,则可能错误设置了其中一个元素。

在 清单 7 中还需注意实体 bean 的 和 元素,在此必须配置哪些数据库表和列映射到实体 bean 字段。参见 清单 7 中的 元素,其中有两个该配置的示例。

最后一个目录是名为 merge 的 src/resources 目录。该目录的内容与 XDoclet 代码生成的执行方式直接相关。XDoclet 从 Javadoc 标记中提取信息, 但它还将信息合并到 merge 目录内专门命名的文件中。这些合并文件包含 Web 应用程序层的一些配置信息。在项目的 src/resources/merge 目录中, taglibs.xml 文件允许定义应用程序中的所有标记库。当 XDoclet 生成 web.xml 和 struts-config.xml 时,有许多文件合并到其中。

另一个部署计划存在于 src/webapp/WEB-INF/geronimo-jetty.xml 文件中, 如 清单 8 所示。

清单 8. geronimo-jetty.xml

   true

Geronimo 的 M4 版本将 geronimo-jetty.xml 部署计划重命名为 geronimo- web.xml。因此,如果正在使用 M4 版本,则需要删除 清单 8 中的 “/jetty”。 其他所有代码将如 Geronimo M4 文章所述运行。

清单 8 所示的这个部署计划有一个重要的行。如果不将 元素设置为 true,则因为 Geronimo 库中可用类的 冲突,Struts 应用程序将无法运行。将该值设置为 true 会告诉 Geronimo 在查 找类时使用标准 Web 应用程序范围。这意味着,该应用程序隔离于服务器中运行 的其他任何应用程序。但同时还意味着,该应用程序需要的任何类都必须与该应 用程序绑定。

应用程序依赖的所有 .jar 组件绑定在 project.xml 依赖关系部分中指定, 并由 Maven 自动处理。

最后一个配置文件是 project.properties,它驱动大多数构建处理,位于项 目的根目录。该文件是一个仓库,存储 XDoclet 相关信息、有关在 .war 文件中 包含哪些内容的信息,甚至还存储控制 Java 编译器输出格式的属性。

将所有这些元素放在一起要花费大量时间,但希望您能够使用该示例应用程序 作为您前行的垫脚石。

结束语

本文为更大的应用程序提供了非常基本的起始模板。为业务逻辑添加更多 CMP bean 和会话 bean,可以创建一个更有趣的 Web 应用程序。我已经展示了 Maven 构建系统的主要优点,即降低编译和生成最终 .ear 文件的嵌套文件结构的复杂 性。XDoclet 代码生成系统还用于简化生成 EJB 工件、Struts 工件和 Web 应用 程序工件的过程,这些工件是编译最终电话簿应用程序所必需的。使用该示例应 用程序,您现在应该能够利用 Maven 和 XDoclet 来简化您的企业应用程序开发 过程。

Geronimo 开发人员已经按照 Sun J2EE 规范认真构建了服务器本身,并生产 出一种将部署和配置问题与细节严格分离的产品,而这是用容器托管应用程序所 必需的。

本文配套源码

生命不息,奋斗不止,就像我们常说的一句话;

利用Geronimo深入EJBWeb应用程序

相关文章:

你感兴趣的文章:

标签云: