Quartz Job Scheduling Framework[翻译]第十章. J2EE 中使用 Quartz (第一部分)

Java 2 平台企业版定义了基于组件的企业应用开发标准。不管你是否倾向于使用一种开源的 J2EE 服务器,比如 JBoss 或 Geronimo,或者你更希望得到可靠安全的商业服务支持,比如 WebSphere 和 WebLogic,你都能在那些应用服务器中使用几种不同的部署方式使用 Quartz。本章给你示范了在 J2EE 应用服务器中以不同策略部署 Quartz,你也会看到 Quartz 框架更加丰富了 J2EE。

一:假如我有 J2EE,为什么还需要 Quartz?

自从 20 世纪 90 年代末期 J2EE 首次登上舞台以来,开发人员就被某些规格决议和一些表面看来明显缺失的特征所困惑。这没必要去批判规格的制定者,更多的是说明了当有不同意见和议程的独立团体,在尝试达成统一的优先级时,就像联合国进行决议时那样,并不如所想像的那样好。许多必须的特征获得认可,但是一些关键的特征被略去留待以后加入。其中一个让早期规范遗漏的关键特征就是定时器服务。

·我需要定时器服务

许多商业流程需要异步的作业调度。例如,Web 站点通常需要向注册用户发邮件告知他们有新的特性或是邮寄最新期刊。医疗索赔处理公司典型的也是需要在晚上下载医疗数据然后拿来处理后续事情。一个销售多种类型产品公司也许要每个晚上生成销售和佣金信息的数据报表。所有前面的场景都需要一个定时器服务来执行异步的作业。

Java/J2EE 社区对解决定时器服务作过多次的尝试。在早期,厂商在他们的 J2EE 服务器中加入适当的解决方案。(在本章上,述语 J2EE 服务器和 J2EE 容器是指同一概念。)例如,WebLogic 产品中有一些定制的扩展,在 IBM 的 J2EE 服务器中也这么做的。不幸的是,它们是不能兼容的,你不能把组件从一种服务器迁移到另一种服务器中。后来,WebLogic 和 IBM 还有其他的厂商试着开发一套通用的定时器组件。

从 Java 1.3 开始,Sun 在 Java 核心中加入了 java.util.Timerjava.util.TimerTask 类来帮助实现基本的定时器功能。尽管 TimerTimerTask 能满足简单的需求,但有更多的作业调度仅用这两个具体类做不到的,希望你已经明白了这一点。

·Quartz/J2EE 部署模型

现在有两个策略用来在 J2EE 中构架和部署 Quartz。其中之一是,你可以把 Quartz 设计在 J2EE 容器外部作为一个标准的 J2SE 客户端。你很快就会看到,这种方法是最简单的。第二种策略是部署 Quartz  驻留在 J2EE 容器中作为其客户端。这种场景下,J2EE 客户端就是一个像其他 Web 应用程序一样部署 Web 归档 (WAR) 文件。策略的选择有赖于你确切的需求。每一种策略都有其好处与缺点。

·作为 J2SE 客户端运行 Quartz

假如你正需要调用 Enterprise JavaBean (EJB) 的服务,或者要把消息送入到 JMS 的队列或主题中,最简单的配置方式就是在 J2EE 容器之外作为一个 J2SE 程序运行。这时它的功能就像任何别的在容器外运行的程序一样,只是它需要去调用容器内分布式组件上的方法。

我们实际上在前面的章节中使用过这种方式,只是未提及调用 EJB 。你可以创建一个 Quartz 应用,包含了 Quartz 库和作业调度信息,并通过 Home 和 Remote 接口连接到 J2EE 服务器。然后你就可以像其他分布式客户端那样调用 EJB 上的方法了。你也可以新建并插入 JMS 消息让容器中运行的消息驱动 Bean (MDB) 来处理它们。在图 10.1 中显示了这种用法。

图 10.1. Quartz 可作为一个独立的 J2SE 客户端与 J2EE 协同工作

QuartzFigure10.1.JPG

如果你有已存在的 J2EE 组件需要 Quartz 与其交互,并且你不希望或无法对服务器作任何改变,用这种这种方法很适合。你只需要像我们前面章节介绍的那样构建一个 Quartz 应用,并使用 Quartz 自带的 EJBInvokerJob。我们马上就会讨论到 EJBInvokerJob 的。

·部署 Quartz 到 J2EE 服务器中

Quartz 也直接能部署在容器中,这样就不需要外部的 Quartz 应用了。这通常被称之为 J2EE 客户端。你选择这种方式也不是之前的方式也许有多个理由。其中之一是你仅需要维护一个应用,而另一种方式需要维护两个应用。中,可以让 Quartz 使用某些容器提供的资源,例如邮件会话、数据源和其他的适配器资源。假如你是在集群环境中使用 J2EE 服务器,这也让部署在容器中的 Quartz 集群更简单和易于管理。图10.2 描绘了 Quartz 如何部署与 J2EE 应用一同部署的。

图 10.2. Quartz 可与 J2EE 应用一同部署
QuartzFigure10.2.JPG

当 Quartz 被部署在 J2EE 容器中,你必须清楚并能处理一些兼容性的问题,在论及这个话题之前,让我们来讨论如何部署 Quartz 为 J2SE 客户端并从容器外访问容器。

·作为 J2SE 客户端运行 Quartz

到目前为止,最简单容易的在 J2EE 中使用 Quartz 的方式是把它部署在容器之外。这种方式这所以简单一方面是因为你无需去处理许多问题,比如 Quartz 如何尝试在 J2EE 容器中创建线程并执行他们的;另一方面是因为即使你使用最新的工具和技术,例如 XDoclet 或管理控制台,部署应用到 J2EE 容器中也是让人感到沮丧的。

·使用 Quartz 的 EJBInvokerJob 去调用 EJB

Quartz 框架中包含 org.quartz.jobs.ee.ejb.EJBInvokerJob 类,它允许你部署一个 Job 当触发时去调用 EJB 的方法。不管你选择的是哪种 Quartz 部署方式,这个 Job 都很容易建立并使用。我们假定,你有一个像代码 10.1 所列的无状态会话 Bean (SLSB)。

代码 10.1. 一个无状态会话 Bean 的例子

 

把这个 EJB 部署到你所选的 J2EE 应用服务器中并准备就绪,你就可以使用 EJBInvokerJob 去调用其中的一个对于远程客户端可见方法 helloWorld()

你只要像其他的 Job 那般建立 EJBInvokerJob。代码10.2 展示了如何用 EJBInvokerJob 去调用那个 SLSB 上的 helloWorld() 方法。

代码 10.2. 一个使用 EJBInvokerJob 的简单例子

正如你在代码 10.2 中看到的,EJBInvokerJob 采用和别的 Job 一样的配置方式。创建了一个相关的 JobDetail 和 trigger 并注册到调度器中。需要针对不同的 J2EE 容器来配置 JobDataMap 中的参数,才能让 Job 正确的执行。表 10.1 列出了这个 Job 所支持的 JobDataMap 参数。

要往 JobDataMap 中加入什么参数依赖于所使用的 J2EE 服务器和自身的需求。例如,假如你使用的是 BEA 的 WebLogic,你必须至少指定代码 10.1 中所列的参数。显示地,必须替换为你特定环境的参数值。假如你是用的 WebSphere,大部份参数值是不一样的。

当我们建立好 Job 并在我们的外部 Quartz 应用程序中运行 10.2 中的代码,每隔 10 秒钏 EJB 上的方法 helloWorld() 就被调用一次。这种方式好就好在我们不需要为部署 Quartz 应用到 J2EE 容器上而费心。这也强制了 Job 信息与商业处理逻辑的分离。

表 10.2. EJBInvokerJob 所用的参数,具体依赖于特定的 J2EE 服务器
静态常量 字面值
 
EJB_JNDI_NAME_KEY
注:Bean 的 home 接口的 JNDI 名
ejb
PROVIDER_URL
注:特定于厂商的 URL,指示哪里能找到服务器
java.naming.provider.url
INITIAL_CONTEXT_FACTORY
注:特定于厂商的上下文工厂,用于查找资源的
java.naming.factory.initial
EJB_METHOD_KEY
注:在 EJB 上要调用的方法名称
method
EJB_ARGS_KEY
注:Object[] 类型,传递给方法的参数值对象数组(可选,如果不设表明无参数)
args
EJB_ARG_TYPES_KEY
注:Class[] 类型,传递给方法参数类型的类数组(可选,如果不调表示每个参数的类型都源自于相应参数的 getClass() 返回) 
argsTypes
PRINCIPAL
注:调用 EJB 方法的主体(用户)
java.naming.security.principal
CREDENTIALS
注:调用 EJB 方法的凭证
java.naming.security.credentials

在代码 10.2 所示例子中,在 EJB 上被调用的方法 helloWorld() 没有定义任何参数。EJBInvokedJob 类允许你通过指定 EJB_ARGS_KEYEJB_ARG_TYPES_KEY 属性来传递方法参数,见表 10.1。

代码 10.3 展示了另一个简单的例子,传递一个参数来调用运行在 Apache Geronimo J2EE 服务器中的 EJB  的另一版本的  helloWord() 方法。

代码 10.3 和代码10.2 十分相像,除多包含了 EJB_ARGS_KEYEJB_ARG_TYPES_KEY 参数设置。还因为 EJB 是运行在 Geronimo J2EE 应用服务器中,所以还需要加上参数 PRINCIPALCREDENTIALS

代码 10.3. 使用 EJBInvokerJob 的简单例子

EJBInvokerJob 参数和序列化

在论及 Java 和分布式程序时会遇到一个典型的问题就是序列化,你应该尽量的传递 String 或原始数据类型给 EJB 的方法。假如你需要传递复杂的类型,你的代码必须使对象在服务端和客户端之间序列化传输。要知道关于 Java 序列化的深层次的信息,请在 http://java.sun.com/j2se/1.5.0/docs/guide/serialization 查看 Sun 的序列化规范。

由于 Quartz 需要拿到 EJB 的 home 和远程接口,你必须部署某些 J2EE 客户端 JAR 包到你外部的 Quartz 应用中。需要哪些 JAR 文件依赖于你所用的 J2EE 容器。例如,假如你是用的 WebLogic,则要在 Quartz 应用程序中引入 weblogic.jar 包。是 Geronimo 的话,就得引入多个相关包。查看特定应用服务器的文档来确保这一点。

类别: Quartz. 标签: , . 阅读(123). 订阅评论. TrackBack.

Leave a Reply

Be the First to Comment!

avatar
wpDiscuz