内容


将第三方组件集成到 Geronimo 中

使用 GBeans 集成开放源码项目 —— 比如 OpenSymphony Quartz

Comments

GBean 架构

Apache Geronimo 应用服务器提供了一种巧妙的架构设计,其中的内核对它的任何组件没有任何的直接依赖关系。内核是服务的框架,控制着服务生命周期和注册表。内核不基于 Java™ 2 Platform, Enterprise Edition (J2EE)。它使用服务和组件来构建特定配置 —— 其中一个是完全的 J2EE 堆栈。大多数 Geronimo 服务器是通过 GBeans 被添加并配置成为整个应用服务器的一部分的。GBean 是连接组件与内核的接口。每个 GBean 可以维护状态,依赖其他 GBean 并与它们相互关联,以及操作来自内核和其他 GBean 中的事件。图 1 展示了带有 GBean 的 Geronimo 内核的图形描述。

图 1. 带有 GBean 的 Geronimo 内核
带有 GBean 的 Geronimo 内核
带有 GBean 的 Geronimo 内核

可以通过称为 计划 的配置文件用控制反转 (Inversion of Control, IoC) 和依赖注入将 GBean 插入内核中。这意味着可以通过计划中的 XML 声明来使用 Geronimo 中的 GBean,而且可以通过属性和引用来配置对其他 GBean 的依赖关系。清单 1 展示了示例 GBean 配置。

清单 1. 示例 GBean 配置
<gbean name="DefaultThreadPool" class="org.apache.geronimo.pool.ThreadPool">
    <attribute name="keepAliveTime">5000</attribute>
    <attribute name="poolSize">30</attribute>
    <attribute name="poolName">DefaultThreadPool</attribute>
</gbean>>

该架构最有趣的部分是,可以通过编辑计划文件和更改 GBean 的 XML 声明,来向 Geronimo 堆栈添加和删除完整组件。

大多数 GBean 允许其他开放源码项目和代码(比如 Jetty、Tomcat 和 OpenEJB)成为 Geronimo 堆栈的一部分,并为这些组件提供 JSR-77 生命周期能力。强大的基于 Java 的组件的一个示例是 OpenSymphony 的 Quartz 调度器。本文展示了如何创建 Quartz GBean 以将 Quartz 调度器集成到 Geronimo 中。

Quartz 调度器

大多数应用服务器不具有无需进行大量修改而运行 cron 或 daemon 作业的能力。虽然一些应用服务器提供了 API 以创建类似 daemon 的应用程序,但它们几乎全部都缺少丰富而完整的特性集。

由 OpenSymphony 开发的 Quartz 是一个功能强大的基于 Java 的开放源码调度器。它的特性包括自定义调度、调度持久性(可以与许多类型的持久性机制一起使用)、远程调度能力、容错、集群,等等。虽然可以独立运行 Quartz,但它的丰富特性使它成为 J2EE 应用服务器堆栈包含物的最佳候选项。可以通过创建启动和停止调度器服务的 GBean 来将 Quartz 集成到 Geronimo 中。

开发 GBean

开发 GBean 是只需要几个步骤的简单任务。要开发 GBean,需要从不稳定的(或 Milestone 4 (M4))分支中下载 Geronimo 源代码,并熟悉如何构建 Geronimo(参阅 参考资料 中 Geronimo Wiki 的链接以获得更多信息)。GBean 可以具有属性、引用和操作。最低限度地,每个 GBean 必须坚持下列指导方针:

  1. 实现 org.apache.geronimo.gbean.GBeanLifecycle 接口,如果想要处理生命周期事件的话。
  2. 提供构造函数。
  3. 实现 doStart()doStop()doFail() 方法。
  4. 提供描述构造函数的 GBeanInfo 静态初始化器。
  5. 实现 public static GBeanInfo getGBeanInfo() 方法。
  6. 创建计划或编辑现有计划,以使用 GBean。

记住这些指导方针,每个 GBean 在最低限度上应与 清单 2 所示的构架类似。

清单 2. 示例 GBean 构架
/**
 * Quartz GBean
 */
public class QuartzGBean implements GBeanLifecycle {
    private static final Log log = LogFactory.getLog(QuartzGBean.class);
    public QuartzGBean() {
    }
    public void doFail() {
        log.info("Service failed");
        //Insert failure code here
    }
    public void doStart() throws Exception {
        log.info("Starting service");
	    //Insert startup code here
    }
    public void doStop() throws Exception {
        log.info("Stopping service");
	    //Insert stopping code here
    }
    public static final GBeanInfo GBEAN_INFO;
    static {
        GBeanInfoBuilder infoFactory = new GBeanInfoBuilder("QuartzGBean",
                QuartzGBean.class);
        GBEAN_INFO = infoFactory.getBeanInfo();
    }
    public static GBeanInfo getGBeanInfo() {
        return GBEAN_INFO;
    }
}

我使用最低限度 来强调,是因为所有 GBeans 都必须包含如 清单 2 所示的声明和实现。如果使用非默认构造函数,或者如果需要属性、引用或可调用操作,则 GBEAN_INFO 静态初始化器需要分别调用 setConstructor()addAttribute()addReference()addOperation()。因为本实例没有任何特殊的构造函数、操作、属性或引用,所以不需要这些调用。

Quartz 是一个要与 GBean 集成的大项目,因为它仅需要您用 Geronimo 应用服务器的生命周期来启动和停止它。这意味着,当 Geronimo 启动时,您想要 Quartz 启动,当 Geronimo 关闭时,您想要 Quartz 停止。

为了保持本示例的简单性,Quartz 配置使用 Quartz 发行版附带的默认值。这些默认值位于 quartz.properties 文件中,该文件是 .jar 文件的一部分。要配置 Quartz 以将数据库用于持久层、远程调度和其他高级选项,必须创建自定义的 quartz.properties 文件。(参阅 参考资料 以链接到 OpenSymphony Web 站点,获得有关配置这些选项的详细信息。)

Quartz 调度器易于启动和关闭;它只通过调用 StdSchedulerFactory.getDefaultScheduler() 来检索调度器对象。要启动 Quartz,执行 Scheduler.startup() 方法。要停止 Quartz,执行 Scheduler.shutdown() 方法。要使 Quartz 的生命周期跟随 Geronimo,将 startup() 调用放入 GBean 的 doStart() 方法中,并将 shutdown() 调用放入 GBean 的 doStop() 方法中。清单 3 展示了添加 Quartz 代码之后完整的 GBean。

清单 3. 新 QuartzGBean
package org.apache.geronimo.quartz;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.geronimo.gbean.GBeanInfo;
import org.apache.geronimo.gbean.GBeanInfoBuilder;
import org.apache.geronimo.gbean.GBeanLifecycle;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.impl.StdSchedulerFactory;
/**
 * Quartz GBean
 */
public class QuartzGBean implements GBeanLifecycle {
    private static final Log log = LogFactory.getLog(QuartzGBean.class);
    public QuartzGBean() {
    }
    public void doFail() {
        log.info("Service failed");
        try {
            doStop();
        } catch (Exception e) {
            log.error("doStop() failed", e);
        }
    }
    public void doStart() throws Exception {
        log.info("Starting service");
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
       scheduler.start();
    }
    public void doStop() throws Exception {
        log.info("Stopping service");
        try {
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            scheduler.shutdown();
        } catch (SchedulerException se) {
            log.error("Cannot shutdown scheduler.", se);
        }
    }
    public static final GBeanInfo GBEAN_INFO;
    static {
        GBeanInfoBuilder infoFactory = new GBeanInfoBuilder("QuartzGBean",
                QuartzGBean.class);
        GBEAN_INFO = infoFactory.getBeanInfo();
    }
    public static GBeanInfo getGBeanInfo() {
        return GBEAN_INFO;
    }
}

QuartzGBean 代码看起来似乎够简单,但仍需要编译它并构建合适的 .jar 文件。因为 Geronimo 使用 Apache Maven 作为构建工具,所以本例为 Quartz 使用了 Maven 模块(参阅 参考资料 以链接到 Maven Web 站点)。要创建 Maven 模块,需要 project.xml 文件、project.properties 文件、maven.xml 文件和您的源代码。本文可供下载的代码包含完整的 Maven 构建模块,用于用 Geronimo 编译 QuartzGBean。要编译该代码,请完成下列步骤:

  1. 将档案文件下载到 geronimo/modules 目录,并在此解压。这将创建一个 quartz 目录,构建基础设施位于该目录下,其中包括 QuartzGBean.java 代码和单元测试。
  2. 确保您位于 geronimo/modules/quartz 目录,并在命令行键入 maven。这将编译、单元测试 GBean,并将其打包到 geronimo-quartz-1.0-snapshot.jar 文件中,该文件存储于您的 Maven 资源库中。

将 QuartzGBean 集成到 Geronimo 中

既然已经创建了 .jar 文件,现在需要对 Geronimo 构建进行少量更改以使用您的 GBean。创建 GBean 时,通常创建用于部署 GBean 的计划。这种情况下,您将编辑一些现有文件以在服务器启动时启动 GBean,而无需手动启动或部署配置。下列步骤将配置 Geronimo 来使用新 QuartzGBean。

  1. 将 Quartz 版本添加到 Geronimo 构建中,以便 Maven 将自动下载合适的版本。 通过添加下列行来编辑位于 geronimo/etc 目录的 project.properties 文件:
    quartz_version=1.4.5
  2. 准备程序集模块以使用 Quartz 和新 .jar 文件。在 geronimo/modules/assembly 目录中,将 清单 4 中的黑体代码增加到依赖关系部分中的 project.xml 文件中:
    清单 4. 程序集 project.xml 依赖关系
    <dependencies>
    .
    .
    .
    <!--Quartz -->
    <dependency>
        <groupId>opensymphony</groupId>
        <artifactId>quartz</artifactId>
        <version>${quartz_version}</version>
        <properties>
            <repository>true</repository>
        </properties>
    </dependency>
    <dependency>
        <groupId>geronimo</groupId>
        <artifactId>geronimo-quartz</artifactId>
        <version>${pom.currentVersion}</version>
        <properties>
            <repository>true</repository>
        </properties>
    </dependency>
    .
    .
    .
    </dependencies>

    <repository>true</repository> 代码导致 Geronimo 构建将 .jar 文件添加到包含最终 Geronimo 程序集的 .jar 资源库中,所以 Geronimo 构建将附带指定的 .jar 文件。

  3. 将 GBean 和依赖关系写入计划中。要确保 QuartzGBean 在 Geronimo 启动时启动,虽然可以创建自己的计划,但编辑现有计划更容易。为此,编辑位于 geronimo/modules/assembly/src/plan 目录中的 j2ee-server-plan.xml 文件。将依赖关系添加到计划中最后一个 </dependency> 标记之后和第一个 <gbean> 标记之前,如 清单 5 所示。
    清单 5. j2ee-server-plan.xml 依赖关系添加
    <!-- Quartz -->
    <dependency>
        <uri>opensymphony/jars/quartz-${quartz_version}.jar</uri>
    </dependency>
    <dependency>
        <uri>geronimo/jars/geronimo-quartz-${geronimo_version}.jar</uri>
    </dependency>
  4. 将 GBean 添加到同一文件。在文件底部的最后一个 </configuration> 标记之前,添加下列行:
    <gbean name="QuartzService" class="org.apache.geronimo.quartz.QuartzGBean"/>

现在只需要重新构建程序集模块。这使得新配置和已更新计划部分成为 Geronimo 服务器的一部分。要重新构建程序集模块,请将目录更改为 geronimo/modules/assembly,并在命令提示行键入 maven。当程序集模块构建完成时,在 geronimo/modules/assembly/target 目录中就会有 geronimo-assembly-1.0-SNAPSHOT.jar 文件了。要运行 Geronimo,请从命令行执行 java -jar bin/server.jar-v-v 通常不是运行 Geronimo 所必需的,但在此包括它是为了将日志输出发送到终端窗口,以便您可以看到发生了什么。

-v 启动 Geronimo 时,记下日志,并观察新 GBean 启动 Quartz,如 清单 6 所示。

清单 6. 带有 QuartzGBean 的 Geronimo 启动日志
14:53:13,462 INFO  [QuartzGBean] Starting service
14:53:13,615 INFO  [SimpleThreadPool] Job execution threads will use class loader of 
                                      thread: main
14:53:13,697 INFO  [RAMJobStore] RAMJobStore initialized.
14:53:13,699 INFO  [StdSchedulerFactory] Quartz scheduler 'DefaultQuartzScheduler' 
                                         initialized from default resource file in 
                                         Quartz package: 'quartz.properties'
14:53:13,699 INFO  [StdSchedulerFactory] Quartz scheduler version: 1.4.5
14:53:13,701 INFO  [QuartzScheduler] Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED 
                                         started.

关闭 Geronimo 时,记下日志中的差别。

清单 7. 带有 QuartzGBean 的 Geronimo 关闭日志
14:53:41,426 INFO  [QuartzGBean] Stopping service
14:53:41,450 INFO  [QuartzScheduler] Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED 
                                     shutting down.
14:53:41,452 INFO  [QuartzScheduler] Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED 
                                     paused.
14:53:41,459 INFO  [QuartzScheduler] Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED 
                                     shutdown complete.

结束语

对于大多数开放源码项目,实现少量函数并编辑少量配置文件是编写 GBeans 所需的全部工作。但是,一些集成计划(比如 Jetty、Tomcat 或 OpenEJB)可能需要在编码中进行更多显著的修改。这些集成在代码中需要多个 GBean、配置和钩子。然而,类似 Quartz 的应用程序是简单集成的优秀候选项,因为它只需要启动和关闭。有很多与 Quartz 一样简单的有助于集成的开放源码项目。

致谢

  • 我想感谢 Apache Geronimo 团队的 Bruce Snyder 和 Dain Sundstrom,他们帮我审阅了本文。
  • 本文同时在 IBM developerWorksVirtuas Solutions 上发表。

下载资源


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Open source, Java technology
ArticleID=93052
ArticleTitle=将第三方组件集成到 Geronimo 中
publish-date=08292005