Quartz入门-v2.2.2

原文地址:Getting Started with Quartz Scheduler
本文中“工作”对应“job”,“任务”对应“task”。关系是工作是若干任务的集合,任务是工作中需要做的具体事情。通俗的例子,“教师”是一个“工作”,它包含的具体“任务”有{“备课”,“上课”,“批改作业”,... }

什么是Quartz Scheduler?

Quartz Scheduler是一个功能丰富的开源的工作调度库,可以被真实地整合到任何Java应用中--从最小的独立应用到最大的电商系统。Quartz可以被用来构建简单或者复杂的调度,用来执行十个、百个或者甚至万个工作。任务被定义为标准的Java组件,这些组件会真实地执行任何你通过编程指定给它们的事情。Quartz Schedulers包含了许多的企业级类的特性,比如它支持JTA事务和集群。

Quartz可以为你做什么?

如果你的应用中有一些任务需要在给定的一个时候及时地执行,或者如果你的系统有一些循环的维护工作,那么Quartz会是你理想中的解决方案。
使用Quartz来工作调度例子:

  • 驱动过程工作流:当一个新的订单被初始化后,调度一个工作来在2个小时内精确的执行,它会检查订单的状态。并且如果一个关于这个订单确认信息还没有收到的话,会触发一个警告通知,同时改变订单的状态为“等待介入”。
  • 系统维护:调度一个工作在每个工作日的11:30PM,去将数据库的内容倒入一个XML文件。
  • 在一个应用中提供提醒服务。

Quartz特色功能


运行时环境

  • Quartz可以嵌入式地运行在另一个完全独立的应用中
  • Quartz可以在一个应用服务器(或者servlet容器)中被实例化,并且加入到XA事务中
  • Quartz可以作为一个独立的程序运行(使用它自己的JVM),通过RMI的方式被使用
  • Quartz可以作为一个独立程序(有着负载均衡和容错能力)的集群被实例化,来执行工作

工作调度

当一个给定的触发器发生的时候,工作将被调度。触发器几乎可以被创建为任何下面的策略,包括:

  • 一天中一个确定的时间(精确到毫秒)
  • 一周中确定的日子
  • 一月中确定的日子
  • 一年中确定的日子
  • 在一个注册的日历中排除一些确定的日子(比如法定假日)
  • 重复一个确定的次数
  • 重复直到一个确定的时间/日期
  • 无限重复
  • 延迟一段时间重复

工作被它们的创建者给定名字,并同样可以通过组名将它们分组。触发器同样会被指定名字并放入组中,为了更容易地在调度过程中组织它们。工作可以被一次性地添加到调度器中,然而被多个触发器所注册。在一个企业级的Java环境中,工作会执行它们的任务作为一个分布式(XA)事务的一部分。

工作执行

  • 工作可以是任何实现了简单Job接口的Java类,为你工作能做的事情留下了无限的可能。
  • 工作类的实例可以通过Quartz被实例化,活着通过你的应用的框架。
  • 当一个触发器发生的时候,调度器会通知0个或更多Java对象去实现JobListener和TriggerListener接口(listener可以是简单的Java对象,或者EJB,或者JMS发布者,等等)。这些监听器在工作执行以后同样会被通知。
  • 当工作完成,它们返回一个JobCompletionCode来告诉调度器是成功还是失败。JobCompletionCode同样会指示调度器的任何它应该根据成功/失败码所进行的行为,比如立刻重新执行工作。

工作持久化

  • Quartz的设计包含了一个JobStore接口,它可以被实现来提供各种各样的机制来存储工作。
  • 通过使用JDBCJobStore,所有的工作和触发器都被配置为“non-volatile”被通过JDBC存储在一个关系型数据库中。
  • 通过使用RAMJobStore,所有的工作和触发器都被存在RAM中,并且在程序执行之间不会持久化--但是这有一个好处就是不需要一个外部的数据库。

事务

  • Quartz可以参与到JTA事务中,通过使用JobStoreCMT(一个JDBCJobStore的子类)。
  • Quartz可以管理JTA事务(开始并提交它们)在工作执行的时候,以便于工作在做的事情在一个JTA事务中可以自动地发生。

集群特性

  • 提供容错
  • 提供负载均衡
  • Quartz的内建集群特性依赖于通过JDBCJobStore的数据库实例化。
  • Terracotta对Quartz提供的扩展提供了集群能力,而不需要一个后端的数据库。

监听器 & 插件

  • 应用可以通过实现一个或多个监听器接口来捕获调度时间来监视或者控制job/trigger的行为。
  • 插件机制可以被用来添加功能到Quartz,如此保持一个工作执行的历史,或者从一个文件中加载job和trigger。
  • Quartz通过整合一些“工厂构建”插件和监听器来运行。

下载和安装Quartz


首先,从http://quartz-scheduler.org/downloads下载最新的稳定版本。注册不是必须的。解压发行包并安装使得你的应用可以看到它。

Quartz的jar文件

Quartz的包里有若干jar文件,在发行包的根目录下。主要的Quartz库的名字叫做quartz-xxx.jar(xxx是版本号)。为了使用任何Quartz的特性,这个jar必须放置在你应用的classpath下面。
如果你使用Quartz主要在一个应用服务器的环境,你可以将Quartz JAR放置在你的应用中(.ear或者.war文件)。如果你想使Quartz对于许多应用都可用,确保它在你应用服务器中classpath下面。如果你正在一个独立的应用中使用它,将它放置在应用的classpath下,并把你应用所依赖的其它JAR文件也放置过去。
Quartz依赖若干第三方的库(通过jar的形式),它们在.zip发布包的lib目录下。为了使用Quartz的所有特性,这些jar必须同样存在于你的classpath下。如果你在构建一个独立的Quartz应用,请添加所有的库到classpath下。

注意:在一个应用服务器的环境,如果环境中包含不同版本的相同的jar包,那么不可预见的结果可能会出现。比如,WebLogic包含一个J2EE的实现(在weblogic.jar里),这有可能和servlet.jar中的那个不同。在这种情况下,将servlet.jar排除在你的应用之外通常是更好的做法,以便于你知道哪个类正在被使用。

属性文件

Quartz使用一个叫做quartz.properties的属性文件。这个文件最初不是必须的,但是当你想要使用任何基本配置以外的东西时,就需要用到它。当你使用这个文件,它必须在你的classpath下面。
如果你在构建一个web应用(比如,一个.war文件的形式),你可以将quartz.properties文件放在WEB-INF/classes文件夹下,从而放置在了应用的classpath下。

提示:如果你使用WebLogic Workshop开发你的应用,你可以保留你的配置文件(包括quartz.properties)在你应用的根目录下面的一个项目中。当你打包你的应用到一个.ear文件中时,配置项目将会把最终的.ear中包含的打包到一个.jar中。这样做将会自动的将quartz.properties文件放置在你的classpath下。

配置Quartz调度器


为了配置Quartz,你编辑quartz.properties文件,并把它放置在你的application的classpath下面。

注意:Quartz调度器的发布包中包含了若干quartz.properties文件的例子在example/directory中。

下面的例子展示了一个基本的quartz.properties文件的内容:

org.quartz.scheduler.instanceName = MyScheduler
org.quartz.threadPool.threadCount = 3
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

这个例子指定了以下的属性:

  • org.quartz.scheduler.instanceName属性为调度器分配了一个名字为“MyScheduler”。
  • org.quartz.threadPool.threadCount属性在线程池中分配了三个线程,意味着最多三个job同时进行。
  • org.quartz.jobStore.class属性配置调度器去使用RAMJobStore来进行数据存储。这意味着调度器将会保持这个job和trigger的数据在内存中而不是数据库。

开始一个示例应用


下面的代码获取一个调度器实力,启动它,然后关闭它。
Quartz.java

import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.impl.StdSchedulerFactory;
import static org.quartz.JobBuilder.*;
import static org.quartz.TriggerBuilder.*;
import static org.quartz.SimpleScheduleBuilder.*;

注意:一旦你使用StdSchedulerFactory.getDefaultScheduler()获得了一个调度器,你的应用将会一直运行直到你调用了scheduler.shutdown()。因为这将是活动的线程。

注意这里使用了static引入,这将在下面的代码中发挥作用。
如果你还没有设置日志,日志的信息将会被发送到console中。你的输出将像下面这样:

[INFO] 21 Jan 08:46:27.857 AM main [org.quartz.core.QuartzScheduler]
Quartz Scheduler v.2.0.0-SNAPSHOT created.
[INFO] 21 Jan 08:46:27.859 AM main [org.quartz.simpl.RAMJobStore]
RAMJobStore initialized.
[INFO] 21 Jan 08:46:27.865 AM main [org.quartz.core.QuartzScheduler]
Scheduler meta-data: Quartz Scheduler (v2.0.0) 'Scheduler' with instanceId 'NON_CLUSTERED'
  Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
  NOT STARTED.
  Currently in standby mode.
  Number of jobs executed: 0
  Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 50 threads.
  Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support
        persistence. and is not clustered.
[INFO] 21 Jan 08:46:27.865 AM main [org.quartz.impl.StdSchedulerFactory]
Quartz scheduler 'Scheduler' initialized from default resource file in Quartz
         package: 'quartz.properties'
[INFO] 21 Jan 08:46:27.866 AM main [org.quartz.impl.StdSchedulerFactory]
Quartz scheduler version: 2.0.0
[INFO] 21 Jan 08:46:27.866 AM main [org.quartz.core.QuartzScheduler]
Scheduler Scheduler_$_NON_CLUSTERED started.
[INFO] 21 Jan 08:46:27.866 AM main [org.quartz.core.QuartzScheduler]
Scheduler Scheduler_$_NON_CLUSTERED shutting down.
[INFO] 21 Jan 08:46:27.866 AM main [org.quartz.core.QuartzScheduler]
Scheduler Scheduler_$_NON_CLUSTERED paused.
[INFO] 21 Jan 08:46:27.867 AM main [org.quartz.core.QuartzScheduler]
Scheduler Scheduler_$_NON_CLUSTERED shutdown complete.

为了做一些事情,你需要在start()shutdown()的调用之间提供一些代码。你将同样需要允许一些时候在调用shutdown()之前,对job进行触发和执行。对于一个简单的像这样的例子,你应该调用:

Thread.sleep(60000);
// define the job and tie it to our HelloJob class
JobDetail job = newJob(HelloJob.class)
    .withIdentity("job1", "group1")
    .build();
// Trigger the job to run now, and then repeat every 40 seconds
Trigger trigger = newTrigger()
    .withIdentity("trigger1", "group1")
    .startNow()
    .withSchedule(simpleSchedule()
            .withIntervalInSeconds(40)
            .repeatForever())
    .build();
// Tell quartz to schedule the job using our trigger
scheduler.scheduleJob(job, trigger);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容