Enhydra 简介
上个月,我们了解了 XMLC,这是一个用于显示动态 Web 内容的新系统,它随 Enhydra 应用服务器一起提供。本月,我们将了解如何使用 Enhydra 附带的工具编写 servlet 和基本应用程序。虽然 Enhydra 的 Web 应用程序不如 Jakarta-Tomcat 的 servlet 那样标准化,但它们确实提供了相当大的功能,并有可能使用完全开源的基础架构创建 Enterprise JavaBeans。
Enhydra 是一个用 Java 编写的开源应用服务器,旨在完全符合 Sun 的 J2EE 规范。 Lutris 公司是 Enhydra 开发的先锋,已根据类似 BSD 的许可证提供该应用服务器。 Enhydra 当前的稳定版本是 3.x,包括对大量标准的支持,包括 servlet 和 JSP。 Enhydra Enterprise 计划于 2001 年夏季发布,将具有额外的 J2EE 功能,包括对 Enterprise Java Beans (EJB) 的支持。
Enhydra 本身作为一个完全开源的产品提供,这意味着您可以从 Web 下载并安装它。但是对于那些可能对开源软件持怀疑态度的客户,他们希望使用经过质量保证的打包产品,或者希望获得 Lutris 的支持,可以使用 Enhydra 的商业版本。我怀疑阅读本专栏的大多数人都不需要 Lutris 的支持,但很高兴知道他们随时准备并愿意帮助其他人使用该产品。
Lutris 的目标市场不仅是 J2EE 市场,还有无线互联网应用程序市场。我个人还没有看到蜂窝互联网技术的引人注目的用途——我手机上的 WAP 功能充其量只能说是可悲——但 Lutris 将 Enhydra 定位为未来必然成为热门市场的参与者。
虽然 Enhydra 尚未发展到 Zope 和 ArsDigita 社区系统的知名度或社区规模,但他们已经取得了一些令人印象深刻的商业胜利。特别是,惠普公司最近宣布,他们将与 Lutris 合作,在许多应用程序中营销和使用 Enhydra。如果说这还不能证明什么,那至少证明了开源应用服务器在 Web 应用程序开发领域确实占有重要的地位,并且即使对于那些原本可以支付更高费用的公司,它们也能提供令人信服的理由。
现在我们已经回顾了一些背景知识,让我们尝试使用 Enhydra 创建一些基本的 Web 应用程序。当然,首要任务是下载并安装该产品。我决定下载 Enhydra Enterprise 的 Beta 版,这在很大程度上是因为我想体验 EJB 功能。截至 Beta 版发布,Enhydra Enterprise 需要 JDK 1.3,这与之前的版本形成鲜明对比,之前的版本即使在 1.3 发布了相当长一段时间后仍然需要 JDK 1.2。
我下载并解压缩了 Enhydra tar 文件,这在 enhydra4.0 目录下创建了大量文件和目录。您可能会猜到,doc 目录包含文档,lib 目录包含 Enhydra 需要的 .jar 文件,conf 目录包含全局 Enhydra 配置文件。还有一个 bin 目录,其中几乎所有文件都是 shell 脚本(以及 Windows .bat 等效文件),用于执行构成 Enhydra 的各种 Java 程序。
为了确保 Enhydra shell 脚本和 Java 程序知道您安装 Enhydra 的目录,请在 Enhydra 发行版的根目录(我将其称为 $ENHYDRA)中运行 configure shell 脚本。configure 接受一个强制性参数,即 JDK 安装的根目录。configure 修改了许多 Makefile 和其他配置文件,但不会强制重新编译任何代码。运行 configure(不会产生任何可见输出)后,在 $ENHYDRA 中运行 bash shell 脚本 (setup.bash),它会将 JDK 可执行文件目录添加到您的 PATH 中。
Enhydra 由许多不同的相互关联的软件包组成。应用服务器本身(称为 multiserver)可以直接与 HTTP 客户端配合使用,也可以与前端 Web 服务器(如 Apache)作为代理配合使用。您可以通过更改 $ENHYDRA/conf/bootstrap.conf 中的 loadOrder 属性来减少 multiserver 启动的服务数量或更改它们的启动顺序。
要启动 multiserver,只需运行 $ENHYDRA/bin/multiserver。它应该立即启动,一次启动一个服务,直到您最终看到消息“Bootstrapper initialized normally”。此时,您可以通过将 Web 浏览器指向端口 8001 来测试 multiserver,这将打开一个控制面板,用于查看 multiserver 的当前状态。
我最初启动 multiserver 的尝试失败了,程序抱怨说无法在我的 CLASSPATH 中找到 enhydra.jar。特别令人困惑的是,我在整个 Enhydra 发行版中都找不到名为 enhydra.jar 的文件。
解决方案结果很简单,即使不是很明显:Enhydra 知道运行其每个程序所需的 CLASSPATH,但如果您已经设置了 CLASSPATH,它将忽略这些设置。因此,在运行 multiserver 之前,请确保取消设置 CLASSPATH,删除此环境变量。完成此操作后,multiserver 应该会按预期启动。
在过去的几个月中,我们了解了 Java servlet 和 JavaServer Pages。 Enhydra 作为一个符合 J2EE 规范的应用服务器,完全支持这些技术。此外,作为开源服务器,Enhydra 使用 Jakarta-Tomcat 引擎作为其 servlet 和 JSP 的基础。正如我们稍后将看到的,使用 Enhydra 自己的高级 Web 应用程序形式是可能的(通常也是更可取的)。
使用 Enhydra 附带的工具创建 servlet 相对容易。事实上,Enhydra 的作者花费了大量时间创建了一个系统,该系统不仅在部署时功能强大,而且在开发过程中也相对容易使用。
如果您习惯于简单地编写 servlet、编译它并将其放入目录中,那么您会发现 Enhydra 会妨碍您,使过程复杂化。这在很大程度上是由于 Enhydra 应用程序的部署方式——Enhydra 期望您希望独立于任何其他应用程序测试(和运行)许多 Web 应用程序,而不是需要外部服务器。
要创建简单的 servlet,我们将使用 Enhydra 附带的应用程序生成向导 (appwizard),您可以将其作为 $ENHYDRA/bin/appwizard 调用。 appwizard 不是 IDE,而是一个复杂的复制文件程序,它提供了一个已经可以工作的基本骨架应用程序。
当您首次运行 appwizard 时,它会询问您是否要开发 Web 应用程序(即标准 servlet)还是 Enhydra 超级 servlet。选择标准 Web 应用程序;超级 servlet 将在稍后介绍。下一个屏幕将询问您是否要以 HTML 或 WML 格式生成输出,后者是蜂窝互联网应用程序的标准基于 XML 的格式。我们将使用 HTML,并将项目目录和包都称为“atf”。默认情况下,Enhydra 应用程序放置在您主目录下的 enhydraApps 子目录中。选择您的代码将根据其发布的许可证,appwizard 将为您的新应用程序生成文件。
事实上,appwizard 创建了大量自动生成的文件和目录。其中包括
一个全局 Makefile,允许我们构建应用程序。在许多应用程序子目录中也有单独的 Makefile。
config.mk,它定义了 Makefile 依赖的许多环境变量,其中包含诸如 Enhydra 版本、JDK 安装位置和 Enhydra 安装位置等信息。
src 目录,其中包含 Java servlet 和 HTML 文件的源代码。 src 下是一个标准的 WEB-INF 目录,其 web.xml 文件命名了我们计划部署的每个 servlet。 atf 目录,其名称取决于我们创建的项目,包含四个子目录:business、data、presentation 和 resources。我们最感兴趣的两个目录是 presentation 和 resources 目录,因为前者包含 servlet,后者包含 HTML 文件和 JSP。
要构建应用程序,只需在我们的项目根目录中运行 make 即可。(Enhydra Enterprise 文档大肆宣传它现在使用基于 Java 的 Ant 构建工具而不是 make,但应用程序创建似乎仍然依赖于 make。)
make 完成其工作后,在我们的应用程序的顶层将有一个新的 output 子目录,与 src 和 input 并行。 output 目录包含启动应用程序所需的一切内容,包括包含我们的 .class 文件、XML 描述符、JSP 和图像的标准 Java .war(Web 存档)文件
WEB-INF/classes/atf/presentation/WelcomeHTML.class WEB-INF/classes/atf/presentation/WelcomeServlet.class WEB-INF/classes/atf/presentation/RedirectServlet.class media/Enhydra.gif index.jsp WEB-INF/web.xml
请注意,这里我们有三个 .class 文件,而 src/atf/presentation/ 中只有两个。这是因为 XMLC 将 src/resources 中的 HTML 文件转换为 Java 源代码文件,然后将其转换为 Java .class 文件。
因此,仅使用 appwizard 和 make 这两个命令,我们就成功创建了一个完整的、正在运行的 Enhydra 应用程序。该应用程序目前没有执行任何特别复杂或有趣的操作,但它为我们提供了一个骨架,我们可以对其进行修改和扩展。
要运行我们的应用程序,我们运行 output/start4。这将在端口 9000(在 input/conf/servlet/servlet.conf.in 中定义)上启动应用程序。如果您将 Web 浏览器指向 http://localhost:9000/,您将看到我们的 servlet 的输出:Enhydra 徽标、我们的应用程序名称 (atf)、当前时间和日期以及一个将您重定向回应用程序的超链接。
HTML 页面由 XMLC 生成,并演示了 XMLC 如何集成到 Enhydra 的其余部分。 XMLC 将 src/atf/resources/Welcome.html 编译为 Java servlet,然后将其转换为 .class 文件。 XMLC 创建的 Java 类包含文件中每个 <span> 标记的钩子,允许检索和修改带有 ID 属性的 <span> 标记中的任何内容。
WelcomeServlet 是最初在我们的应用程序中执行的 servlet,它通过创建 XMLC 生成的类的实例来显示当前时间和日期
now = DateFormat.getTimeInstance(DateFormat.MEDIUM) .format(new Date()); welcome = new WelcomeHTML(); welcome.getElementTime().getFirstChild() .setNodeValue(now);
换句话说,我们通过将 HTML 文件转换为 DOM 可访问的树,然后更改特定节点的值,来替换 ID 为“time”的 <span> 标记中的文本。
要向我们的应用程序添加其他 servlet,我们可以编写 servlet 并将其保存在 src/atf/presentation 中。请注意,包将是 atf.presentation,而不仅仅是 atf。我们将编写一个非常简单的类 Foo,您可以在列表 1 中看到它。除了包名称外,传统 servlet 和 Foo.java 之间没有任何区别。
现在我们需要告诉 servlet 引擎将 URL 映射到我们的 servlet。我们在 src/WEB-INF/web.xml 中执行此操作。此 XML 文件分为两个部分:第一部分将 servlet 类映射到 servlet 名称,第二部分将 servlet 名称映射到 URL。列表 2 包含 web.xml 的修改版本,用于处理映射我们的 Foo servlet。
最后,我们需要在 Makefile 中包含我们的新类,将我们的类名添加到 CLASSES 变量中
CLASSES = WelcomeServlet \ RedirectServlet Foo
运行 make 并检查 Foo.class 是否已添加到应用程序中,方法是:
jar tvf output/archive/atf.war如果一切正常,则运行 output/start4,并将您的浏览器指向 http://localhost:9000/foo。您应该看到由我们的新 Foo servlet 交付的 HTML 输出。
经验丰富的 Web 开发人员,无论使用哪种语言或环境,都习惯于为每个网页编写单独的程序。如果您想显示五个不同的动态生成的页面,那么您必须编写五个不同的 CGI 程序、mod_perl 处理程序、servlet 或 JSP 页面。
Enhydra 允许开发人员摆脱这种模式,从应用程序而不是单个页面的角度进行思考。实现此目的的方法是使用超级 servlet,顾名思义,其中单个应用程序对象与多个表示对象相关联。
您可以轻松地在 Enhydra URL 中识别表示对象;后缀 .po 告诉 Enhydra 它应该调用 URL 中命名的对象。因此,请求 Abc.po 将执行表示对象 Abc 的 run() 方法。与标准 Java servlet 不同,表示对象为每个 HTTP 请求实例化一次。这可能不如在单个 servlet 实例上使用多个线程效率高,但它确实消除了编写线程安全 servlet 代码相关的麻烦。
因此,一个简单的 Enhydra 应用程序将至少包含一个应用程序对象,以及至少一个表示对象。这些 PO(众所周知)可以连接到 Enhydra 的其他两个主要对象类型:业务对象(执行常用功能)和数据对象(将持久存储(如关系数据库)映射到 Java 类)。正如我们已经看到的,这三种类型的对象(表示、业务和数据)中的每一种都在应用程序的 src 子目录中都有自己的目录。此外,这些对象中的每一个都构成了三层 Web 应用程序中的三个标准层之一。因此,虽然可能需要一段时间才能习惯对象类型之间的分离,但这种模型在 Web 应用程序中正变得越来越普遍。
我们将再次使用 Enhydra 的 appwizard 来创建一个我们可以更改的骨架应用程序。再次运行 appwizard,但在第一个屏幕上的选择列表中选择超级 servlet,而不是简单的 Web 应用程序。我选择将项目称为 myproject,并将其放在 il.co.lerner 包中,这是我在公司内部项目中使用的包。appwizard 然后在 ~/enhydraApps/myproject 中创建一个骨架应用程序。该应用程序的结构与我们的 servlet 类似,目录结构也类似。在 src/il/co/lerner 下,我们有 presentation、data 和 business 目录。同样,还有一个顶层 Makefile,它将编译并创建我们的超级 servlet。
查看 presentation/WelcomePresentation.java,这是最终将显示的表示对象的源代码。事实上,如果我们键入顶层目录中的 make,运行 output/start4 以启动我们的应用程序,并将 Web 浏览器指向 http://localhost:9000/,我们会发现我们的浏览器被重定向到 http://localhost:9000/WelcomePresentation.po。此页面显示与我们的骨架 servlet 打印的相同的示例输出,带有 Enhydra 徽标以及当前时间和日期。
正如我们已经知道的,po 后缀告诉 Enhydra 调用 WelcomePresentation 中的 run() 方法。在自动创建的骨架应用程序中,WelcomePresentation.run() 看起来像列表 3。
列表 3. WelcomePresentation.run()
超级 servlet 接口与常规 servlet 的接口类似,并且对于熟悉 servlet 的程序员来说,学习起来并不需要花费太多时间。 run() 方法接受 HttpPresentationComms 类型的单个参数,该参数为我们的表示对象提供其与外部世界的所有通信需求,包括 HTTP 请求和响应对象。
run() 方法通过创建 WelcomeHTML 的实例来显示输出,WelcomeHTML 是 XMLC 从文件 Welcome.HTML 创建的 Java 类。之后,run() 将 ID 为“time”的 <span> 标记的内容替换为当前日期和时间。然后,我们将包含 DOM 树的 welcome 的内容写入 HTTP 响应对象。
我们可以创建我们自己的表示对象 FooPresentation,如列表 4 所示。请记住将新对象添加到 presentation 目录的 Makefile 中的 CLASSES 行。当您从顶层应用程序目录重新运行 make 时,FooPresentation 将被编译并插入到我们的 Enhydra 应用程序中。
能够编写我们自己的表示对象非常好,但是控制它们的应用程序对象在哪里呢?在主源代码目录中,与 presentation、data 和 business 目录位于同一级别,有一个 Java 类文件,其名称与项目相同——因此在我们的例子中,在 src/il/co/lerner/myproject.java 中有一个文件。
到目前为止,我们仅在独立的 multiserver 之外运行了我们的超级 servlet。此功能非常适合希望能够测试应用程序而不会干扰主要生产网站的开发人员,但我们希望在某个时候将我们的应用程序添加到该服务器。
Enhydra 使这项工作相对容易完成:我们将有关我们应用程序的信息添加到 multiserver 的配置文件中,以便它可以找到该应用程序。然后,我们使用 multiserver 的控制面板将我们的应用程序添加到生产服务器中,URL 由我们选择。此时,我们的应用程序将可供全世界访问。
为了完成此操作,我们必须再次使用 shell 脚本 $ENHYDRA/bin/multiserver 启动 multiserver。这使 multiserver 在端口 8001 上可用。在浏览器中加载管理屏幕,并查看左上角可用应用程序的列表。
现在我们将复制应用程序配置文件(而不是应用程序本身),名为 output/conf/myproject.conf,并将其复制到全局 multiserver 目录 $ENHYDRA/apps。然后编辑 $ENHYDRA/apps/myproject.conf,更改 Server.ClassPath[] 的值。在 myproject.conf 中,Server.ClassPath[] 已经有两个可能的值:一个用于在独立模式下运行应用程序,另一个用于在 multiserver 下运行应用程序。注释掉(第一个)独立值,并取消注释(第二个)multiserver 值。
完成此操作后,返回到您的 Web 浏览器,然后单击 multiserver 控制面板中的“添加”按钮(上面有一个大的 + 号)。我们将添加一个新的应用程序,其名称 (myproject) 应在选择列表中。为此应用程序选择一个根 URL,并为您想要的此应用程序组输入任何文本字符串。单击“确定”以添加应用程序。
现在刷新 multiserver 控制面板。在左上角,您应该看到“myproject”,以及当前可能已加载的任何其他应用程序。如果您单击 myproject 名称,屏幕的右侧将填充有关 myproject 的信息。
要运行该应用程序,我们需要为我们的应用程序定义一个或多个连接,然后运行它。默认情况下,我们的应用程序将在端口 8002 和 8003 上运行;如果需要,我们可以添加一个或多个新连接。定义连接后,单击屏幕左侧的“运行”按钮。连接 URL 将变为超链接,单击其中一个超链接将打开与我们的 Web 应用程序的连接——Enhydra 徽标和当前时间——显示在一个新窗口中。(我通常觉得 JavaScript 和新窗口很烦人,但 Enhydra 作者以某种方式设法平衡了品味和功能,并提供了一个外观不错的 Web 界面。)
我们可以通过更改 URL 来测试我们的 FooPresentation 对象,将 WelcomePresentation.po 替换为 FooPresentation.po。果然,我们在浏览器中看到了我们简单的 Foo HTML 输出。
我们可以使用基于 Web 的控制面板从一个或多个端口或从 multiserver 完全删除我们的应用程序。最后,我们可以使用控制面板或通过按 Ctrl-C 在我们启动它的终端窗口中关闭 multiserver。
编写 servlet 本身并不困难,但 Enhydra 提供的远不止 servlet。特别是,它们提供了一个环境,可以轻松编写和测试 servlet,而无需运行完整的 Web 服务器。此外,Enhydra 提供的超级 servlet 可能比常规 servlet 更易于使用,特别是由于我们可以避免处理线程问题以及为每个页面编写新的整体处理程序应用程序。
当然,也存在一些缺点。 Enhydra 像大多数 Java 程序一样,在设置 CLASSPATH 时需要相当多的耐心。(尽管值得称赞 Lutris,删除我自己的 CLASSPATH 几乎解决了所有这些问题。)虽然 Enhydra 的自动生成的 Makefile 大大减少了您在创建完成的 Web 应用程序时必须投入的思考量,但 Java 程序似乎总是需要比它们的 Perl 和 Python 对等程序多十倍的文件。
虽然超级 servlet 肯定比它们的非超级同类产品有所改进,但我总是会在跳入一项偏离已知、文档齐全且成熟的标准的技术之前犹豫不决——特别是当开源社区似乎正在慢慢地团结在 Enhydra 周围时。最后,虽然 Enhydra Enterprise 确实还不是一个发布的产品,但安装说明和文档还有待改进。
尽管有所有这些保留意见,但我仍然很容易看到自己在未来的 Java 开发中使用 Enhydra,而不是我过去使用的普通的 Jakarta-Tomcat。 XMLC 和集成环境的结合在许多方面都非常有吸引力。
正如我之前提到的,我对 Enhydra Enterprise 最兴奋的原因之一是它能够连接到 Sun 的 Enterprise JavaBeans。在接下来的两个月中,我们将更仔细地研究 Enhydra,首先研究其 DODS 工具,用于将关系数据库映射到 Java 对象。然后,我们将涉足 EJB 的世界,证明仅仅因为我们依赖开源产品并不意味着我们的工具比专有程序员的工具逊色。
Reuven M. Lerner 拥有一家小型咨询公司,专门从事 Web 和互联网技术。他与妻子 Shira 和女儿 Atara Margalit 一起住在以色列的 Modi'in。您可以通过 reuven@lerner.co.il 或 ATF 主页 www.lerner.co.il/atf 与他联系。