将数据库连接到 Geronimo 应用服务器的三种方法 在 Geronimo 中设置 JDBC 数据库 |
|
级别: 初级
Neal Sanche (neal@nsdev.org), Java 开发人员和作者
2005 年 7 月 18 日
您是否需要将您的数据库连接到为 Geronimo 编写的 Web 应用程序?Geronimo 出现的时间虽然不长,但它是模块化的而且结构设计优良。您可以使用三种方法中的任意一种将数据库连接到 Geronimo 应用服务器;每种方法都将创建一个不同类型的 Java™ 数据库连接(Java™ Database Connectivity,JDBC)数据源。下面将使用所包括的示例应用程序和可以下载的 Eclipse IDE 项目来学习如何将组件结合在一起,并通过 Geronimo 中部署的 JDBC 连接池使您的应用程序达到预期效果。
要在 Apache Geronimo 应用服务器中建立 JDBC 数据源,您需要:
- 安装了最低为 Milestone 3 (M3) 版本的 Geronimo 的服务器。请参阅参考资料,查看下载 Geronimo 的链接。
- 了解一些 J2EE 概念,如 JSP、标签库、部署描述符以及如何将 Web 应用程序打包到 .war 文件中。(在开发示例应用程序时,将会向您介绍这些主题中的大部分。因此,如果您是才接触 Java™ Web 应用程序开发,也可以接着看下文。)
- 一些运行数据库服务器的经验。本文包括使用 MySQL 进行数据库访问的详细信息。尽管如此,但还想告诉您的是:您可以方便地替换示例文件中的任何数据库服务器和 JDBC 驱动程序,以便在示例中使用您喜欢的数据库。
可以通过三种方法将数据库连接到 Geronimo 应用服务器:
- 创建一个供许多应用程序使用的服务器范围的全局数据源。
- 将 JDBC 连接池嵌入单一部署的企业应用程序中。但是,当使用此方法时,该应用程序必须作为 .ear 文件进行绑定。
- 创建模块范围的 JDBC 数据源,该数据源能够严格控制应用程序的哪些部分可以访问数据库。
目前,只有 Web 应用程序对数据库具有模块范围的访问权。但 Geronimo 小组讨论了在即将实际发行的 1.0 版本中使用其他类型的应用程序模块进行模块范围的访问。
本文将介绍把数据库连接到 Geronimo 应用服务器的三种方法,并提供了一个使用这些概念的示例应用程序。该示例应用程序将在以后的文章中进一步阐述,以验证更多的 J2EE 堆栈。但目前,我们将验证 Web 应用程序(Servlet 和 JSP 层)以及 J2EE 堆栈的 JDBC 连接器层。
Geronimo 是一个能够承载许多不同应用程序组件的灵活的应用服务器。Geronimo 使用部署计划帮助应用程序部署系统判断应用程序的各个组件应有的位置。J2EE 规范将一些部署详细信息留给应用服务器提供商进行定义。Apache Geronimo 小组目前使用部署计划告诉服务器哪些部分可用,以及如何对它们进行配置和部署。
对于 Web 应用程序,部署的 .war 文件将包含一个名为 geronimo-jetty.xml 的部署计划,它与 web.xml 文件共同位于 Web 应用程序的 WEB-INF 目录中。此部署计划可帮助 Geronimo 服务器提供最终的应用程序详细信息,如 Web 应用程序环境的根目录是什么(在用户浏览器中键入时,应用程序的 URL 的路径部分),以及应用程序可能需要的任何资源引用。在看过示例 Web 应用程序后,这一点就会更清楚。如果您熟悉 XML 模式定义 (XML Schema Definition) 语言(并不是所有的人都熟悉),则可以看一看 $geronimo-root$/schema/geronimo-jetty.xsd 文件,从中可以了解将哪些内容归入部署计划。而且在将来,当所有 XML 编辑器都支持 XML 模式时,我们将能够使用 XML 编辑器来创建符合该模式的完美的 XML 文件。现在您必须学会读懂一些模式。
企业应用程序模块可以通过部署计划进行类似的扩展。这些打包在 .ear 文件中的模块将在 META-INF 目录中拥有一个 geronimo-application.xml 部署计划和 application.xml 文件。在查看 geronimo-application.xsd XML 模式文件后,您可能会了解此部署计划使您能够构建 configId、parentId、应用程序名称和依赖关系。依赖关系很有用,当部署应用程序时,它允许应用服务器加载应用程序,正确运行所需的内容。在下文中还将看到更多关于 geronimo-application.xml 的信息。
|
要创建可以由 Geronimo 服务器中多个应用程序使用的全局数据源,必须创建一个部署计划,并将其正确地部署到服务器。这可以通过创建 XML 文件来完成,该文件向服务器描述如下详细信息:要创建哪些应用程序组件,它们的配置参数应该是什么,配置所具有的依赖关系是什么。
通常,打包在 .jar 文件中的 JDBC 驱动程序是所有组件正确工作所必需的依赖关系。Geronimo 有一个专门位置来保存包含所有这些必需的依赖关系的 .jar 文件。您只能在 Geronimo 服务器的主目录中看到名为 repository 的子目录,该子目录依次包含每个要声明的共享组件的子目录。在其中的每个子目录中,都有一个 jars 子目录,所需的文件都存放在这个子目录中。
由于要连接到本地 MySQL 数据库,因此我们从 MySQL 网站下载了 mysql-connector-java-3.1.8-bin.jar 文件(请参阅参考资料中提供的到此站点的链接)。在名为 mysql 的存储库下创建一个目录,并将 .jar 文件放在一个 jars 目录中。
现在您需要为 J2EE 连接器创建一个部署计划。注意,在 XML 文件中有一个 dependency 元素,该元素指定了 JDBC 驱动程序 .jar 所在的库目录的 URI 路径。要对它进行修改,使它满足您的数据库,请编辑 UserName、Password、Driver 以及 ConnectionURL 的 configId 和 config-property-setting 元素,如清单 1 所示。
清单 1. 编辑 configId 和 config-property-settings 元素
<?xml version="1.0"> <connector xmlns="http://geronimo.apache.org/xml/ns/j2ee/connector" version="1.5" configId="MysqlDatabase" parentId="org/apache/geronimo/Server"> <dependency> <uri> mysql/jars/mysql-connector-java-3.1.8-bin.jar </uri> </dependency> <resourceadapter> <outbound-resourceadapter> <connection-definition> <connectionfactory-interface> javax.sql.DataSource </connectionfactory-interface> <connectiondefinition-instance> <name>MysqlDataSource</name> <config-property-setting name="UserName"> geronimo </config-property-setting> <config-property-setting name="Password"> geronimo </config-property-setting> <config-property-setting name="Driver"> com.mysql.jdbc.Driver </config-property-setting> <config-property-setting name="ConnectionURL"> jdbc:mysql://localhost/geronimo </config-property-setting> <config-property-setting name="CommitBeforeAutocommit"> false </config-property-setting> <config-property-setting name="ExceptionSorterClass"> org.tranql.connector.NoExceptionsAreFatalSorter </config-property-setting> <connectionmanager> <local-transaction/> <single-pool> <max-size>10</max-size> <min-size>0</min-size> <blocking-timeout-milliseconds> 5000 </blocking-timeout-milliseconds> <idle-timeout-minutes> 30 </idle-timeout-minutes> <match-one/> </single-pool> </connectionmanager> <global-jndi-name> jdbc/MysqlDatabase </global-jndi-name> </connectiondefinition-instance> </connection-definition> </outbound-resourceadapter> </resourceadapter> </connector> |
将 XML 文件另存为 mysql-plan.xml,以便明确它是 MySQL 数据库的一个部署计划。然后,部署该文件。要部署该文件,将用到 Geronimo Deploy 命令。由于这是一个 J2EE 连接器 (J2EE Connector),因此还需要 tranql/rars 下 Geronimo 库中的 tranql-connector-1.0-SNAPSHOT.rar 文件。可以将 XML 文件放入 Geronimo 根目录,并使用下面的命令从该目录中完成部署。
在一行中键入下面的这一个命令。由于空间原因,该命令在这里被分成了两行。
$ java -jar bin/deployer.jar mysql-plan.xml repository/tranql/rars/tranql-connector-1.0-SNAPSHOT.rar |
系统会提示输入用户名和密码,默认的用户名和密码分别为 system 和 manager。如果您使用的是 UNIX® 操作系统,那么请将反斜杠改为正斜杠。如果一切顺利,该命令将会由 Deployed MysqlDatabase 响应。如果更改了 configId,则会引用更改的内容。如果出现问题,请参考 Geronimo 日志进行调试。
|
第二种数据库配置范围是应用程序范围的数据源。创建全局 JDBC 数据源部分中描述的 mysql-plan.xml 文件的文件格式可以继续在此类部署中使用。下面的过程用于将数据库访问信息直接嵌入应用程序的 .ear 文件。
首先,在简介中已经提到,您需要创建 META-INF/geronimo-application.xml 部署计划,如下图所示:
清单 2. 创建 META-INF/geronimo-application.xml 部署计划
<application xmlns="http://geronimo.apache.org/xml/ns/j2ee/application" configId="MyApplication"> <module> <connector>tranql-connector-1.0-SNAPSHOT.rar</connector> <alt-dd>mysql-plan.xml</alt-dd> </module> </application> |
接着,将 tranql-connector-1.0-SNAPSHOT.rar 文件绑定到 .ear 文件。并且像 bundled .ear 文件中的任何其他模块一样,将其引用到 application.xml 文件(模块元素中的连接器元素)。这里的关键是,部署计划中添加了 mysql-plan.xml 文件,以提供连接器配置的信息(在 alt-dd 元素中)。不要忘记将 mysql-plan.xml 文件绑定到 application .ear 文件中。
|
第三种类型的数据库配置范围对于 Geronimo 来说可能是最独具特色的。显然,Geronimo 小组已构想了对数据源进行彻底的限定范围的访问,并且努力将数据源访问的精确程度提高到模块级别。这与许多应用服务器不同,多数应用服务器只允许使用应用程序范围的数据源或全局范围的数据源。此模块级范围提供了一个抽象级别(数据隐藏),允许您限制数据库对特定模块的可见性。这意味着其他模块无法修改此数据库。这减少了出现问题时在多层应用程序体系结构中需要遵守的调试路径。
要完成此类配置,只须将连接器元素从 mysql-plan.xml 文件中删除,并将其嵌入 geronimo-jetty.xml 文件的一个新资源元素中即可,该文件位于以下代码中以粗体突出显示的文本之间:
清单 3. 将连接器元素嵌入新资源元素中
<web-app xmlns="http://geronimo.apache.org/xml/ns/web/jetty" xmlns:naming="http://geronimo.apache.org/xml/ns/naming" ...> ... <resource> <external-rar> tranql/rars/tranql-connector-1.0-SNAPSHOT.rar </external-rar> <!-- Place the connector element, verbatim, below --> <connector </connector> </resource> |
从上面可以看到,tranql-connector-1.0-SNAPSHOT.rar 文件必须放在 $GERONIMO_HOME/repository 目录的适当子目录中才起作用,在新配置的服务器中也应如此。
为什么要使用此类数据库配置范围?如果希望确保某个数据库表仅能够用于您的 Web 应用程序组件,而不是能够用于其他任何组件或应用程序,则此类方法较为理想。它的理想效果表现在不需要部署额外的文件,原因是 tranql.rar 文件是一个共享资源。其他的优点是只须在 geronimo-jetty.xml 文件中额外添加一些文本,就可以嵌入应用程序的数据库配置,这意味着将来可以较容易地群集化 Web 应用程序。
|
为了描述如何使用数据源,我编写了一个小应用程序,该程序使用前面描述的 mysql-plan.xml 文件部署的全局范围的数据库连接器。选择此方法是看中了它的简单性,并且我只需要考虑开发一个已在 .war 文件中部署的 Web 应用程序即可。因此应用程序范围的部署并不适用(它仅用于 .ear 文件部署计划)。因此,在此情况下,我们可以从全局范围部署或模块范围部署方法中进行选择。
本文包括一个小型的 Eclipse IDE 项目,您可以下载它。该项目中包括一个 Ant 脚本,用于构建示例应用程序,并将其部署到您的 Geronimo 服务器。我是使用 Eclipse 3.1M6 和某个版本的 Lomboz EJB 插件(可选)来组织代码的。当然,您不必按我这种方式来部署应用程序。
下面的图 1 中显示了示例项目的文件树组织。图中列出了由若干 Java 源文件、一个 .jsp 文件、一些支持部署描述符和 Geronimo 部署计划组成的标准 Web 应用程序源代码布局。其中包括了我喜欢的一个 JSP 标签库 DisplayTag(请参见参考资料中提供的链接),该标签库可以很容易地以表格方式显示 Java 对象集。另外,它还为您显示了如何在 Geronimo 环境中包括和使用 JSP 标签库。
图 1. Eclipse 示例项目文件的结构
使用下面的 MySQL 命令创建数据库,并对其授权,然后向这个数据库中添加一个表:
清单 4. 使用 MySQL 命令设置数据库
$ mysql -u root -p mysql password: **** > create database geronimo; > grant all on geronimo.* to geronimo@127.0.0.1 identified by 'geronimo'; > grant all on geronimo.* to geronimo@localhost identified by 'geronimo'; > use geronimo; Database Changed > create table phone ( name varchar(255) primary key, phone varchar(255) ); > insert into phone ('Ralph Nader', '555-2221'); > insert into phone ('Albert Einstein','555-2222'); |
创建这个简单的数据库后,将看到(在清单 5 中)一个返回 PhoneBookEntry 对象列表的类。通过执行 JNDI 查找来获得资源映射的数据源,该类可以获得一个 JDBC 连接。实现这些操作的代码显示在 org.acme.phonebook 数据包下的 phonebook/JavaSource 目录中。
清单 5. getPhoneList() 方法返回一个 PhoneBookEntry 对象列表
/** * Obtain a phone list from a JDBC Datasource. */ public Collection getPhoneList() throws NamingException, SQLException { ArrayList list = new ArrayList(); InitialContext ctx = new InitialContext(); DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/DataSource"); Connection con = null; Statement stmt = null; ResultSet rs = null; try { con = ds.getConnection(); stmt = con.createStatement(); rs = stmt.executeQuery("select name,number from phone"); while (rs.next()) { PhoneBookEntry entry = new PhoneBookEntry(rs.getString("name"), rs.getString("number")); list.add(entry); } return list; } finally { if (ctx != null) ctx.close(); if (rs != null) rs.close(); if (stmt != null) stmt.close(); if (con != null) con.close(); } } |
您可以看到,通过使用 lookup() 方法,请求名为 java:comp/env/jdbc/DataSource 的 DataSource 的 InitialContext 实例(这里称为 ctx),可以获得数据源。然后,可以使用 DataSource 从池中获取数据库连接,最后使用该池在结果集中执行查询和迭代,并返回 PhoneBookEntry 对象的结果列表。
您可能会问在何处指定 java:comp/env/jdbc/DataSource 名称。这项指定操作一部分发生在 web.xml 文件中,还有一部分发生在 geronimo-jetty.xml 部署计划中。
下面是它在 web.xml 文件中的表现形式:
清单 6. 在 web.xml 文件中指定 java:comp/env/jdbc/DataSource 名称
<resource-ref> <res-ref-name>jdbc/DataSource</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> <res-sharing-scope>Shareable</res-sharing-scope> </resource-ref> |
下面是它在 geronimo-jetty.xml 文件中的表现形式:
清单 7. 在 geronimo-jetty.xml 文件中指定 java:comp/env/jdbc/DataSource 名称
<naming:resource-ref> <naming:ref-name>jdbc/DataSource</naming:ref-name> <naming:resource-link>MysqlDataSource</naming:resource-link> </naming:resource-ref> |
您可以看到,在 web.xml 文件中建立了 jdbc/DataSource 别名。在 geronimo-jetty.xml 文件中,引用被链接到以前部署 mysql-plan.xml 时定义的 MysqlDataSource。
要确保在部署应用程序时自动加载 MysqlDataSource,可以将 geronimo-jetty.xml 文件中 web-app 元素的 parentId 属性设置为 MysqlDatabase。这将告诉 Geronimo,在进行部署时,Web 应用程序需要首先启动数据库部署。这是一个很好的依赖机制。
|
编写 Web 应用程序的方法有许多。您可以编写 servlets,引入 XML/XSLT 模板引擎或只编写 HTML。也可以编写 JSP,它极其类似于 HTML,其中带有允许 Java 代码嵌入页面的 XML 小标记。它还允许名为标签库的模块,并将该模块嵌入到应用程序中,增加可以添加到 HTML 的 XML 标签的数量,并提供有用的功能。在 Geronimo 中编写 JSP 页并没有什么特殊之处。Geronimo 支持的 Web 容器 Jetty 是一个业已建立的容器,它具有卓越的性能,并由享有盛誉的开发团队提供支持。
示例应用程序中的 JSP 仅例示了一个 Java 对象,并使用 DisplayTag 标签库以表格格式显示各项。该代码特别简单,并且可以在清单 8 中找到。
清单 8. index.jsp 文件
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib uri="http://displaytag.sf.net" prefix="display" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Geronimo Phonebook</title> </head> <body> <jsp:useBean id="phonelist" class="org.acme.phonebook.PhoneList" scope="request"/> This is a test application to show very simple database access. <display:table name="phonelist.phoneList"/> </body> </html> |
现在,您需要一个简单的 build.xml 文件,以便将它用于 Ant 构建系统。只要 build.xml 文件配置了正确的属性,您就能够在示例文件的主目录中键入 ant,并构建它。
在 build.xml 文件中,有一个 Ant 任务,如清单 9 所示。
清单 9. build.xml 中的 Ant 任务
<target name="deploy" depends="compile,package" description="--> A simple Geronimo Phonebook JDBC Application"> <java jar="${geronimo.root}/bin/deployer.jar" fork="true"> <arg value="--user"/> <arg value="${geronimo.user}"/> <arg value="--password"/> <arg value="${geronimo.password}"/> <arg value="undeploy"/> <arg value="PhoneBookWeb"/> </java> <java jar="${geronimo.root}/bin/deployer.jar" fork="true"> <arg value="--user"/> <arg value="${geronimo.user}"/> <arg value="--password"/> <arg value="${geronimo.password}"/> <arg value="deploy"/> <arg value="phonebook.war"/> </java> </target> |
您可以看到,这里执行了 deployer.jar 文件,并请求取消部署 Web 应用程序。在此小应用程序中,我使用了 Ant,根据 Geronimo 开发团队的解释,您也可以考虑使用 Maven 来更方便地自动部署 Geronimo 应用程序。
|
Geronimo 还不太成熟,在尝试执行此示例应用程序时,会不时地表现出这一点。但 Geronimo 也许是最具模块化和架构安排最干净的应用服务器之一,它会继续快速改进。今年有望推出该软件符合标准的 1.0 版本,所有现在值得对它了解一下。
本文概述了在 Geronimo 中部署数据库连接器的三种方法。作为练习,您可以修改 Web 应用程序部署计划来嵌入连接器元素,并将其从全局范围转换为模块范围。
确保在将来文章的若干类似迭代中遵循这一电话簿小应用程序的开发,您将学习有关 Geronimo 的更多功能,以及它与许多其他 J2EE 应用服务器的不同之处。