文章目录

  • 概述
  • Quartz 概述
  • Quartz 基础结构
    • Job
    • JobDetail
    • Trigger
    • Calendar
    • Scheduler
    • ThreadPool
  • 注意
  • 快速入门 Quartz(2.2.X)
    • 增加Maven依赖(Maven工程)
    • Quartz Jar 包
    • 配置文件
    • 配置
  • 实例

概述

任务调度是多数应用系统的常见需求之一,我们直接编写基于现成的调度程序,不但容易出错,而且实现难度很大。 Quartz是任务调度领域非常出色的开源框架,Spring提供了继承Quartz的功能。


首先我们来回归下,常见的定时任务:

  • OS级别的定时任务管理器

例如linux的crontab、windows自带的计划任务。优点是:占用系统资源较少,而且操作简便,是定时任务首选的实现方式,缺点:当任务数量非常大,而且任务与任务之间有因果关系、先后顺序、竞争条件的话,OS级别的定时任务管理器就很难支持了。

  • 编程语言自带的定时任务管理器

例如Java的timer和TimeTask。但是这些API提供的接口功能简单,往往不能满足用户定时任务设置需要,所以在项目开发过程中很少使用。

  • 第三方组件

例如Java的quartz,python的celery等。这些组件往往既可以单独部署,也可以与当前的项目集成在一起统一部署管理,关键是他们有着强大的功能,能够满足我们对定时任务管理的各种需求,所以这些第三方组件往往在项目中应用广泛。


Quartz 概述

Quartz是一个开源的作业调度框架,它完全由Java写成,并设计用于J2SE和J2EE应用中。它提供了巨大的灵 活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度。它有很多特征,如:数据库支持,集群,插件,EJB作业预构建,JavaMail及其它,支持cron-like表达式等等。

Quartz框架是一个全功能、开源的任务调度服务,可以集成几乎任何的java应用程序—从小的单片机系统到大型的电子商务系统。Quartz可以执行上千上万的任务调度。

官网地址:http://www.quartz-scheduler.org

Quartz提供了强大的任务调度机制。 Quartz允许开发人员灵活的定义触发器的调度时间表,并可对触发器和任务进行关联映射。

此外Quartz提供了调度环境运行的持久化机制,可以保存并恢复调度现场,即使系统因故障关闭,调度任务现场数据也不会丢失。

Quartz还提供了组件式的侦听器、各种插件、线程池等功能


Quartz 基础结构

Quartz对任务调度的领域问题进行了高度的抽象,提出了调度器、任务和触发器这3个核心的概念,并在org.quartz通过接口和类对重要的这些核心概念进行描述

Job(任务)、JobDetail(任务细节)、Trigger(触发器)、Scheduler(任务调度器)


Job

Job是一个接口,只有一个接口方法

void execute(JobExecutionContext
context)

我们只需要实现该接口定义需要执行的任务,把任务放在execute中执行即可。

JobExecutionContext类提供了调度上下文的各种信息。Job运行时的信息保存在JobDataMap实例中。


JobDetail

Quartz执行Job时,需要新建个Job实例,但是不能直接操作Job类,所以通过JobDetail来获取Job的名称、描述信息。 Quartz在每次执行Job时,都重新创建一个Job实例,但是它不直接接受一个Job的实例,相反它接收一个Job实现类,以便运行时通过newInstance()的反射机制实例化Job。

因此需要通过一个类来描述Job的实现类及其它相关的静态信息,如Job名字、描述、关联监听器等信息,JobDetail承担了这一角色。

重要属性如下:

  • name:任务的名称。

  • group:任务所在的组(默认值:DEFAULT)。

  • jobClass:任务的实现类。

  • jobDataMap:传参的作用。


Trigger

Trigger是一个类,执行任务的规则。这个触发器实现了 Trigger 接口。描述触发Job执行的时间触发规则。主要有SimpleTriggerCronTrigger这两个子类。

  • 当仅需触发一次或者以固定时间间隔周期执行,SimpleTrigger是最适合的选择;

  • CronTrigger则可以通过Cron表达式定义出各种复杂时间规则的调度方案:如每早晨9:00执行,周一、周三、周五下午5:00执行等;


Calendar

org.quartz.Calendar和java.util.Calendar不同, 它是一些日历特定时间点的集合(可以简单地将org.quartz.Calendar看作java.util.Calendar的集合——java.util.Calendar代表一个日历时间点,无特殊说明后面的Calendar即指org.quartz.Calendar)。

一个Trigger可以和多个Calendar关联, 以便排除或包含某些时间点。

假设,我们安排每周星期一早上10:00执行任务,但是如果碰到法定的节日,任务则不执行,这时就需要在Trigger触发机制的基础上使用Calendar进行定点排除。

针对不同时间段类型,Quartz在org.quartz.impl.calendar包下提供了若干个Calendar的实现类,如AnnualCalendar、MonthlyCalendar、WeeklyCalendar分别针对每年、每月和每周进行定义


Scheduler

Scheduler是最核心的概念,需要把JobDetail和Trigger注册到scheduler中,才可以执行。

Scheduler代表一个Quartz的独立运行容器Trigger和JobDetail可以注册到Scheduler中,两者在Scheduler中拥有各自的组及名称,组及名称是Scheduler查找定位容器中某一对象的依据,Trigger的组及名称必须唯一,JobDetail的组和名称也必须唯一(但可以和Trigger的组和名称相同,因为它们是不同类型的)。

Scheduler定义了多个接口方法,允许外部通过组及名称访问和控制容器中Trigger和JobDetail。

Scheduler可以将Trigger绑定到某一JobDetail中,这样当Trigger触发时,对应的Job就被执行。

一个Job可以对应多个Trigger,但一个Trigger只能对应一个Job。

可以通过SchedulerFactory创建一个Scheduler实例。

Scheduler拥有一个SchedulerContext,它类似于ServletContext,保存着Scheduler上下文信息,Job和Trigger都可以访问SchedulerContext内的信息。

SchedulerContext内部通过一个Map,以键值对的方式维护这些上下文数据,SchedulerContext为保存和获取数据提供了多个put()和getXxx()的方法。可以通过Scheduler# getContext()获取对应的SchedulerContext实例。


ThreadPool

Scheduler使用一个线程池作为任务运行的基础设施,任务通过共享线程池中的线程提高运行效率。


Job有一个StatefulJob子接口,代表有状态的任务,该接口是一个没有方法的标签接口,其目的是让Quartz知道任务的类型,以便采用不同的执行方案。

无状态任务在执行时拥有自己的JobDataMap拷贝,对JobDataMap的更改不会影响下次的执行。

而有状态任务共享共享同一个JobDataMap实例,每次任务执行对JobDataMap所做的更改会保存下来,后面的执行可以看到这个更改,也即每次执行任务后都会对后面的执行发生影响。

正因为这个原因,无状态的Job可以并发执行,而有状态的StatefulJob不能并发执行,这意味着如果前次的StatefulJob还没有执行完毕,下一次的任务将阻塞等待,直到前次任务执行完毕。有状态任务比无状态任务需要考虑更多的因素,程序往往拥有更高的复杂度,因此除非必要,应该尽量使用无状态的Job。

如果Quartz使用了数据库持久化任务调度信息,无状态的JobDataMap仅会在Scheduler注册任务时保持一次,而有状态任务对应的JobDataMap在每次执行任务后都会进行保存。

Trigger自身也可以拥有一个JobDataMap,其关联的Job可以通过JobExecutionContext#getTrigger().getJobDataMap()获取Trigger中的JobDataMap。不管是有状态还是无状态的任务,在任务执行期间对Trigger的JobDataMap所做的更改都不会进行持久,也即不会对下次的执行产生影响。

Quartz拥有完善的事件和监听体系,大部分组件都拥有事件,如任务执行前事件、任务执行后事件、触发器触发前事件、触发后事件、调度器开始事件、关闭事件等等,可以注册相应的监听器处理感兴趣的事件。


注意

不同的版本的jar包,具体的操作不太相同,但是思路是相同的;比如1.8.6jar包中,JobDetail是个类,直接通过构造方法与Job类关联。SimpleTrigger和CornTrigger是类;在2.0.2jar包中,JobDetail是个接口,SimpleTrigger和CornTrigger是接口


上图描述了Scheduler的内部组件结构,SchedulerContext提供Scheduler全局可见的上下文信息,每一个任务都对应一个JobDataMap,虚线表达的JobDataMap表示对应有状态的任务.


快速入门 Quartz(2.2.X)

增加Maven依赖(Maven工程)

这里我们使用2.2.3 版本,后续的案例都是基于此版本。

<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.2.3</version>
</dependency>

Quartz Jar 包

Quartz 解压后包含了几个 jar 文件,位于lib目录下。Quartz 的主要包名称为 quartz-xxx.jar(xxx 表示版本号)。

要使用 Quartz 提供的特性,这个 jar 包必须添加到项目的 classpath 中。

Quartz 根目录 /lib 目录下包含了 Quartz 的一系列依赖包。如果要使用 Quartz 的完整功能,那么这些 jar 包也要添加到项目的 classpath 中。

如果需要创建独立的 Quartz 应用程序,那么建议将所有的这些包都添加到项目 classpath 中。

如果你是在 web 服务器中使用 Quartz,那么这些第三方包可能在你的 classpath 中已经存在,这时你需要选择你的项目具体需要哪个 jar 包。


配置文件

Quartz 使用的配置文件是 quartz.properties。如果使用最基本的配置,那么这个文件不是必须的,否则,这个文件必须包含在 classpath 中。

如果你创建的是 web 应用程序,那么 quartz.properties 文件需要部署到 WEB-INF/classes 中,也就是 classpath 中。


配置

Quartz 的最大优势就是可配置。最好的配置方式是编写 quartz.properties 文件并放到项目的 classpath 中。

Quartz 发布包中包含了几个配置文件的例子,它们放在发布包的 /examples 目录下。建议创建新的 quartz.properties 文件进行配置,而不是拷贝例子中的 quartz.properties 文件来修改。这样做的配置文件将会更加整洁,并且你也会学习到更多 Quartz 提供的特性。

作为快速起步,我们配置一个最基本的 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 – 线程池中有 3 个线程,这意味着最多只能同时运行 3 个任务。

  • org.quartz.jobStore.class – 所有 Quartz的数据,例如任务和触发器的数据都存放到内存中(而不是数据库中)。即使你使用了数据库同时也使用了 Quartz,也建议使用 RamJobStore。


实例

现在,我们已经下载并安装了 Quartz,是时候开始编写一个样例程序了。下面的代码得到了一个 Scheduler(调度器),并调用了调度器的开始和结束操作。

package com.xgj.quartz.quartzItself.quickDemo;import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.impl.StdSchedulerFactory;public class QuartzTest {public static void main(String[] args) {try {// Grab the Scheduler instance from the FactoryScheduler scheduler = StdSchedulerFactory.getDefaultScheduler();// startscheduler.start();// shutdownscheduler.shutdown();} catch (SchedulerException e) {e.printStackTrace();}}}

一旦使用 StdSchedulerFactory.getDefaultScheduler() 获得了 Scheduler,那么你的程序将不会停止,除非我们显式调用scheduler 的 shutdown 方法。这是因为一直都有活动的线程。

如果你没有配置日志,那么所有的日志将会在控制台打印:

INFO  StdSchedulerFactory - Using default implementation for ThreadExecutor
INFO  SimpleThreadPool - Job execution threads will use class loader of thread: main
INFO  SchedulerSignalerImpl - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
INFO  QuartzScheduler - Quartz Scheduler v.2.2.3 created.
INFO  RAMJobStore - RAMJobStore initialized.
INFO  QuartzScheduler - Scheduler meta-data: Quartz Scheduler (v2.2.3) 'DefaultQuartzScheduler' with instanceId 'NON_CLUSTERED'Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.NOT STARTED.Currently in standby mode.Number of jobs executed: 0Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.INFO  StdSchedulerFactory - Quartz scheduler 'DefaultQuartzScheduler' initialized from default resource file in Quartz package: 'quartz.properties'
INFO  StdSchedulerFactory - Quartz scheduler version: 2.2.3
INFO  QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
INFO  QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutting down.
INFO  QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED paused.
INFO  QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutdown complete.

如果需要处理我们的任务,需要在 start() 和 shutdown() 方法之间添加代码:

package com.xgj.quartz.quartzItself.quickDemo;import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.TriggerBuilder.newTrigger;import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;public class QuartzTest {public static void main(String[] args) {try {// Grab the Scheduler instance from the FactoryScheduler scheduler = StdSchedulerFactory.getDefaultScheduler();// startscheduler.start();// define the job and tie it to our SimpleJob classJobDetail job = newJob(SimpleJob.class).withIdentity("job1","group1").build();// Trigger the job to run now, and then repeat every 40 secondsTrigger trigger = newTrigger().withIdentity("trigger1", "group1").startNow().withSchedule(simpleSchedule().withIntervalInSeconds(40).repeatForever()).build();// Tell quartz to schedule the job using our triggerscheduler.scheduleJob(job, trigger);// shutdown if needed// scheduler.shutdown();} catch (SchedulerException e) {e.printStackTrace();}}}

SimpleJob.class如下 ,简单的打印时间

package com.xgj.quartz.quartzItself.quickDemo;import java.text.SimpleDateFormat;import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;/*** * * @ClassName: SimpleJob* * @Description: 实现Job接口,定义需要执行的任务。 JobExecutionContext类提供了调度上下文的各种信息。*               Job运行时的信息保存在JobDataMap实例中。* * @author: Mr.Yang* * @date: 2017年10月6日 上午11:56:43*/public class SimpleJob implements Job {@Overridepublic void execute(JobExecutionContext context)throws JobExecutionException {SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");System.out.println(" triggered time is " + dateFormat.format(new java.util.Date()));}
}

运行日志

.......
INFO  QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.triggered time is 2017-10-06 11:07:02triggered time is 2017-10-06 11:07:42triggered time is 2017-10-06 11:08:22
........
........
........
........

我们没有显式的调用shutdown方法,所以一直运行。

Quartz-任务调度概述及Quartz(2.2.X)快速入门相关推荐

  1. Freemarker简单概述及其数据类型的简单学习—快速入门(一)

    FreeMarker的主要学习内容 一.FreeMarker概述 FreeMarker中文官方手册(可结合学习)http://freemarker.foofun.cn/ FreeMarker学习笔记源 ...

  2. 从零开始学 Java - Spring 使用 Quartz 任务调度定时器

    生活的味道 睁开眼看一看窗外的阳光,伸一个懒腰,拿起放在床一旁的水白开水,甜甜的味道,晃着尾巴东张西望的猫猫,在窗台上舞蹈.你向生活微笑,生活也向你微笑. 请你不要询问我的未来,这有些可笑.你问我你是 ...

  3. quartz java spring_从零开始学 Java - Spring 使用 Quartz 任务调度定时器

    生活的味道 睁开眼看一看窗外的阳光,伸一个懒腰,拿起放在床一旁的水白开水,甜甜的味道,晃着尾巴东张西望的猫猫,在窗台上舞蹈.你向生活微笑,生活也向你微笑. 请你不要询问我的未来,这有些可笑.你问我你是 ...

  4. java任务调度定时器,从零开始学 Java - Spring 使用 Quartz 任务调度定时器

    生活的味道 睁开眼看一看窗外的阳光,伸一个懒腰,拿起放在床一旁的水白开水,甜甜的味道,晃着尾巴东张西望的猫猫,在窗台上舞蹈.你向生活微笑,生活也向你微笑. 请你不要询问我的未来,这有些可笑.你问我你是 ...

  5. Spring Quartz 框架结构概述(一)[转]

    Spring Quartz 框架结构概述(一)[转]  标签:scheduler  trigger  jobdatamap  任务调度  quartz   http://www.blogjava.ne ...

  6. 任务调度开源框架Quartz动态添加、修改和删除定时任务

    Quartz 是个开源的作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的机制.Quartz框架包含了调度器监听.作业和触发器监听.你可以配置作业和触发器监听为全局监听或者是特定于 ...

  7. Java任务调度之Quartz快速入门

    首先所谓的任务调度指的是软件系统在从某个时间节点开始,以固定的频率,除去特定的某些时间段,定期执行某项任务,比如可以在某个夜深人静的时候做一些大批量的文件传输.备份等耗费极大资源的工作,那么通过这个概 ...

  8. (转)Quartz任务调度(1)概念例析快速入门

    http://blog.csdn.net/qwe6112071/article/details/50991563 Quartz框架需求引入 在现实开发中,我们常常会遇到需要系统在特定时刻完成特定任务的 ...

  9. Quartz任务调度器详解

    关键字: 参考文章:http://blog.sina.com.cn/s/blog_4d36e1ae0100tost.html 价值文章分享:http://wenku.baidu.com/link?ur ...

最新文章

  1. echarts grid的样式位置_ECharts grid组件配置 提示框浮层的位置
  2. IPSEC的NAT兼容性
  3. 使用Gradle的简单Spring MVC Web应用程序
  4. iphone图片等比缩放
  5. 服务器托管常见问题纠纷与解决方法
  6. 乱谈卡巴CCTV黄金时段广告
  7. 【ElasticSearch】 ElasticSearch 读取 流程
  8. Sleutel:密码治理器
  9. mysql 5.7 sql mode_MySQL 5.7版本sql_mode=only_full_group_by问题
  10. SLAM_相机与imu的融合基础知识
  11. 多思计组原理虚拟实验室_多思计算机组成原理虚拟实验室
  12. fftshift详解
  13. 谷歌Google验证
  14. Dango 之 Xadmin
  15. 新手初学者入门2000左右预算?哪些单板民谣吉他值得推荐。
  16. 5 6c语言上机作业答案,(完整版)C语言考试题库及答案
  17. UDP多播:一对多数据收发
  18. 高性能MySQL 笔记
  19. ToggleButtonBar的使用
  20. SVN windows 快速入门

热门文章

  1. mit risc-v 资料
  2. 矩阵分解法做推荐系统
  3. 数字字符串转化为字母组合的种数
  4. 删除无序单链表中值重复出现的节点
  5. 暴力解决:InvocationException: GraphViz‘s executables not found
  6. 文巾解题 477. 汉明距离总和
  7. MATLAB从入门到精通:MATLAB识别 自带手写数字集的CNN(LeNet5)
  8. 海量数据处理利器之Hash——在线邮件地址过滤
  9. php 根据权重随机数,PHP根据概率产生随机数
  10. lucene实战--打分算法没有那么难!