Quartz笔记(一)

 什么是Quartz


Quartz是一个完全由Java编写的开源作业调度框架,为在Java应用程序中进行作业调度提供了简单却强大的机制。Quartz允许开发人员根据时间间隔来调度作业。它实现了作业和触发器的多对多的关系,还能把多个作业与不同的触发器关联。简单地创建一个org.quarz.Job接口的Java类,Job接口包含唯一的方法:

    public void execute(JobExecutionContext context) throws JobExecutionException;

在Job接口实现类里面,添加需要的逻辑到execute()方法中。配置好Job实现类并设定好调度时间表,Quartz就会自动在设定的时间调度作业执行execute()。

整合了Quartz的应用程序可以重用不同事件的作业,还可以为一个事件组合多个作业。Quartz通过属性文件来配置JDBC事务的数据源、全局作业、触发器侦听器、插件、线程池等等。

Quartz是由James House创建并最初于2001年春天被加入sourceforge工程。接下来的几年里,有很多的新特性和版本出现,但是直到项目迁移到新的站点并成为OpenSymphony项目家族的一员,才开始真正启动并受到也有的关注。

目前的版本已经是2.0以上,v2.x相对于v1.x有很多新特性出现,并有很多的改动,具体参见Quartz官网上说明。这里介绍的仍然是v1.x(v1.8.6)。

 "Hello, Quartz"


配置环境:

1. 下载Quartz

2. 阅读Readme.txt,了解每个jar包的作用,将quartz.jar包和lib/下的几个jar包、以及相关依赖的jar包放在工程的classpath中

先来看一个简单的Quartz应用,让它每隔5s打印"Hello, Quartz",打印10次。

代码清单1:创建任务

import java.util.Date;

import org.quartz.Job;

import org.quartz.JobExecutionContext;

import org.quartz.JobExecutionException;

public class HelloQuartzJob implements Job {

public void execute(JobExecutionContext context)

throws JobExecutionException {

System.out.println("Hello, Quartz! - executing its JOB at "+

new Date() + " by " + context.getTrigger().getName());

}

}

为了调度此任务执行,需要先得到一个Schedule实例,然后创建一个包含任务信息的JobDetail,最后创建一个Trigger管理任务的执行。

代码清单2:调度任务

import java.sql.Date;

import org.quartz.JobDetail;

import org.quartz.Scheduler;

import org.quartz.SchedulerException;

import org.quartz.SchedulerFactory;

import org.quartz.SimpleTrigger;

import org.quartz.impl.StdSchedulerFactory;

public class HelloQuartzScheduling {

public static void main(String[] args)throws SchedulerException
{

SchedulerFactory schedulerFactory = new StdSchedulerFactory();

Scheduler scheduler = schedulerFactory.getScheduler();

JobDetail jobDetail = new JobDetail("helloQuartzJob",

Scheduler.DEFAULT_GROUP, HelloQuartzJob.class);

SimpleTrigger simpleTrigger = new SimpleTrigger("simpleTrigger",

Scheduler.DEFAULT_GROUP);

simpleTrigger.setStartTime(new Date(System.currentTimeMillis()));

simpleTrigger.setRepeatInterval(5000);

simpleTrigger.setRepeatCount(10);

scheduler.scheduleJob(jobDetail, simpleTrigger);

scheduler.start();

}

}

运行结果:

可以看到,其实它执行了11次。此处没有配置log4j.properties属性文件。

整个任务创建及调度的简单示意图如下。

Job接口包含唯一方法execute(),将任务逻辑添加到该方法中。StdSchedulerFactory.getScheduler()返回一个可运行的实例,然后创建调度任务的JobDetail实例,并传递3个参数给构造方法。第一个参数是任务名,用于引用该任务。第二个参数是任务组名,这里使用默认名,任务组名用于引用集合起来的一组任务,如可以使用Scheduler.pauseJobGroup()来暂停一组任务,每个组中的任务名是唯一的。第三个参数是实现特定任务的类。创建JobDetail实例后,需要创建一个Trigger,这里使用的是SimpleTrigger类,它提供了JDK
Timer风格的触发器行为。传递给SimpleTrigger构造方法的两个参数分别是触发器名和任务组名,触发器名在它所在的任务组中必须是唯一的。接下来是设置触发器的一些属性,setStartTime()是设置启动时间,setRepeatInterval()是设置重复间隔,setRepeatCount()是设置重复次数。最后,scheduler.start()启动调度,终止调度可以用stop()方法。

 CronTrigger类


Quartz有两大触发器,除了上面使用的SimpleTrigger外,就是CronTrigger。CronTrigger能够提供复杂的触发器表达式的支持。CronTrigger是基于Unix Cron守护进程,它是一个调度程序,支持简单而强大的触发器语法。

使用CronTrigger主要的是要掌握Cron表达式。Cron表达式包含6个必要组件和一个可选组件,如下表所示。


位置


含义


允许的特殊字符


1


秒(0~59)


, -  *  /


2


分(0~59)


, -  *  /


3


小时(0~24)


, -  *  /


4


日期(1~31)


, -  *  /  ?  L  W  C


5


月(JAN~DEC或1~12)


, -  *  /


6


星期(SUN~SAT或1~7)


, -  *  /  ?  L  C  #


7


年(可选,1970~2099),若为空,表示全部时间范围


, -  *  /

特殊字符的含义,见下表。


特殊字符


说明


*


通配符,任意值


?


无特定值。通常和其他指定的值一起使用,表示必须显示该值但不能检查


-


范围。e.g.小时部分10-12表示10:00,11:00, 12:00


,


列分隔符。可以让你指定一系列的值。e.g.在星期域中指定MON、TUE和WED


/


增量。表示一个值的增量,e.g.分钟域中0/1表示从0开始,每次增加1min


L


表示Last。它在日期和星期域中表示有所不同。在日期域中,表示这个月的最后一天,而在星期域中,它永远是7(星期六)。当你希望使用星期中某一天时,L字符非常有用。e.g.星期域中6L表示每一个月的最后一个星期五


W


在本月内离当天最近的工作日触发,所谓的最近工作日,即当天到工作日的前后最短距离,如果当天即为工作日,则距离是0;所谓本月内指的是不能跨月取到最近工作日,即使前/后月份的最后一天/第一天确实满足最近工作日。e.g.
LW表示本月的最后一个工作日触发,W强烈依赖月份。


#


表示该月的第几个星期,e.g. 1#2表示每一个月的第一个星期一


C


日历值。日期值是根据一个给定的日历计算出来的。在日期域中给定一个20C将在20日(日历包括20日)或20日后日历中包含的第一天(不包括20日)激活触发器。例如在一个星期域中使用6C表示日历中星期五(日历包括星期五)或者第一天(日历不包括星期五)

Cron表达式举例:

"30 * * * * ?" 每半分钟触发任务

"30 10 * * * ?" 每小时的10分30秒触发任务

"30 10 1 * * ?" 每天1点10分30秒触发任务

"30 10 1 20 * ?" 每月20号1点10分30秒触发任务

"30 10 1 20 10 ? *" 每年10月20号1点10分30秒触发任务

"30 10 1 20 10 ? 2011" 2011年10月20号1点10分30秒触发任务

"30 10 1 ? 10 * 2011" 2011年10月每天1点10分30秒触发任务

"30 10 1 ? 10 SUN 2011" 2011年10月每周日1点10分30秒触发任务

"15,30,45 * * * * ?" 每15秒,30秒,45秒时触发任务

"15-45 * * * * ?" 15到45秒内,每秒都触发任务

"15/5 * * * * ?" 每分钟的每15秒开始触发,每隔5秒触发一次

"15-30/5 * * * * ?" 每分钟的15秒到30秒之间开始触发,每隔5秒触发一次

"0 0/3 * * * ?" 每小时的第0分0秒开始,每三分钟触发一次

"0 15 10 ? * MON-FRI" 星期一到星期五的10点15分0秒触发任务

"0 15 10 L * ?" 每个月最后一天的10点15分0秒触发任务

"0 15 10 LW * ?" 每个月最后一个工作日的10点15分0秒触发任务

"0 15 10 ? * 5L" 每个月最后一个星期四的10点15分0秒触发任务

"0 15 10 ? * 5#3" 每个月第三周的星期四的10点15分0秒触发任务

将上面HelloQuartz例子中SimpleTrigger换成CronTrigger,代码如下。

代码清单3:CronTrigger调度器

import java.text.ParseException;

import org.quartz.CronTrigger;

import org.quartz.JobDetail;

import org.quartz.Scheduler;

import org.quartz.SchedulerException;

import org.quartz.SchedulerFactory;

import org.quartz.impl.StdSchedulerFactory;

public class HelloQuartzScheduling {

public static void main(String[] args)

throws SchedulerException, ParseException {

SchedulerFactory schedulerFactory = new StdSchedulerFactory();

Scheduler scheduler = schedulerFactory.getScheduler();

JobDetail jobDetail = new JobDetail("helloQuartzJob",

Scheduler.DEFAULT_GROUP, HelloQuartzJob.class);

String cronExpression = "30/5 * * * * ?"; // 每分钟的30s起,每5s触发任务

CronTrigger cronTrigger = new CronTrigger("cronTrigger",

Scheduler.DEFAULT_GROUP, cronExpression);

scheduler.scheduleJob(jobDetail, cronTrigger);

scheduler.start();

}

}

运行结果:

CronTrigger使用HolidayCalendar类可以排除某一段时间,比如说国庆节不执行调度任务,代码示例如下:

代码清单4:HolidayCalendar的使用

import java.text.ParseException;

import java.util.Calendar;

import org.quartz.CronTrigger;

import org.quartz.JobDetail;

import org.quartz.Scheduler;

import org.quartz.SchedulerException;

import org.quartz.SchedulerFactory;

import org.quartz.impl.StdSchedulerFactory;

import org.quartz.impl.calendar.HolidayCalendar;

public class HelloQuartzScheduling {

public static void main(String[] args)

throws SchedulerException, ParseException {

SchedulerFactory schedulerFactory = new StdSchedulerFactory();

Scheduler scheduler = schedulerFactory.getScheduler();

JobDetail jobDetail = new JobDetail("helloQuartzJob",

Scheduler.DEFAULT_GROUP, HelloQuartzJob.class);

Calendar cal = Calendar.getInstance();

cal.set(2012, Calendar.OCTOBER, 1); // 国庆节

HolidayCalendar holidayCal = new HolidayCalendar();

holidayCal.addExcludedDate(cal.getTime()); // 排除该日期

// addCalendar(String calName, Calendar calendar,

//             boolean replace, boolean updateTriggers)

scheduler.addCalendar("calendar", holidayCal, true, false);

String cronExpression = "30/5 * * * * ?"; // 每5s触发任务

CronTrigger cronTrigger = new CronTrigger("cronTrigger",

Scheduler.DEFAULT_GROUP, cronExpression);

cronTrigger.setCalendarName("calendar");

scheduler.scheduleJob(jobDetail, cronTrigger);

scheduler.start();

}

}

 JobStore: 任务持久化


Quartz支持任务持久化,这可以让你在运行时增加任务或者对现存的任务进行修改,并为后续任务的执行持久化这些变更和增加的部分。中心概念是JobStore接口。默认的是RAMJobStore。

 配置文件


上述没有用到任何的配置文件。Quartz支持配置文件,它的好处是比编写代码简单,且修改后不需要重新编译源码。

>> 配置quartz.properties特性文件

quartz.properties文件定义了Quartz应用运行时行为,还包含了许多能控制Quartz运转的属性。它应放在工程的classpath中。

代码清单5:quartz.properties

#============================================================================

# Configure Main Scheduler Properties

#============================================================================

# 实例名

org.quartz.scheduler.instanceName = QuartzScheduler

# 实例ID

org.quartz.scheduler.instanceId = AUTO

#============================================================================

# Configure ThreadPool

#============================================================================

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool

# 线程个数

org.quartz.threadPool.threadCount = 3

org.quartz.threadPool.threadPriority = 5

#============================================================================

# Configure JobStore

#============================================================================

org.quartz.jobStore.misfireThreshold = 60000

org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

#============================================================================

# Configure Plugins

#============================================================================

org.quartz.plugin.triggHistory.class = org.quartz.plugins.history.LoggingJobHistoryPlugin

# org.quartz.plugins.xml.JobInitializationPlugin是Quartz自带的插件,

# 默认时,这个插件会在 classpath 中搜索名为 quartz_jobs.xml

# 的文件并从中加载 Job 和 Trigger 信息

# v1.8之前用JobInitializationPlugin

#org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.JobInitializationPlugin

org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin

org.quartz.plugin.jobInitializer.fileNames = quartz_jobs.xml

org.quartz.plugin.jobInitializer.failOnFileNotFound = true

org.quartz.plugin.jobInitializer.scanInterval =10

org.quartz.plugin.jobInitializer.wrapInUserTransaction = false

# 关闭quartz新版本检测功能

org.quartz.scheduler.skipUpdateCheck = true

>> 配置quartz_jobs.xml文件

在配置quart_jobs.xml时,遇到一个问题:

Exception in thread "main" org.quartz.SchedulerException: SchedulerPlugin class‘org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin;‘ couldnot be
instantiated.

因为quartz从版本1.8开始,配置文件有所改动,以前quartz自带的插件是JobInitializationPlugin,而1.8中是XMLSchedulingDataProcessorPlugin. xml
schema亦有所改变,难道是改变后配置不对?错误提示是插件类找不到,jar包也都加入到工程了啊。最后终于发现,在quartz.properties特性文件中配置插件行最后多打了个分号。原来是一个多余的分号引发的错误!

下面是新的xml配置文件格式示例。

代码清单6:quartz_jobs.xml格式 

<?xmlversion="1.0"encoding="UTF-8"?>

<job-scheduling-dataxmlns="http://www.quartz-scheduler.org/xml/JobSchedulingData"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.quartz-scheduler.org/xml/JobSchedulingData
http://www.quartz-scheduler.ogr/xml/job_scheduling_data_1_8.xsd"

version="1.8">

<pre-processing-commands>

<!--在执行作业和触犯器之前执行的命令-->

<delete-jobs-in-group>*</delete-jobs-in-group>

<!--删除标示组中的所有作业,如果是“*”,则删除所有组中的作业,同时也会删除与作业有关的触犯器 -->

<delete-triggers-in-group>*</delete-triggers-in-group>

<!--删除标示组中的所有触犯器,如果是“*”,则删除所有组中的触发器 -->

<delete-job>

<!--删除指定的作业,同时也会删除与它关联的触犯器 -->

<name></name>

<group></group>

</delete-job>

<delete-trigger>

<!--删除指定的触犯器 -->

<name></name>

<group></group>

</delete-trigger>

</pre-processing-commands>

<processing-directives>

<!--在计划作业和触发器是应遵循的命令和原则 -->

<overwrite-existing-data>true
or false</overwrite-existing-data>

<!--是否复写已经存在的任务计划数据,如果为false并且ingore-duplicates非false,那么文件中同名的触发器或作业将会继续存在,则会产生错误-->

<ignore-duplicates>true
or false</ignore-duplicates>

<!--如果为true,计划中的任何同名的作业/触发器将会被忽略,不会产生错误-->

</processing-directives>

<schedule>

<job>

<name>JobName</name>

<group>JobGroup</group>

<description></description>

<job-class></job-class>

<job-listener-ref></job-listener-ref>

<!--
volatility,durability,recover必须按顺序设定 -->

<volatility></volatility>

<durability></durability>

<recover></recover>

<job-data-map>

<!--
entry可以设定多个-->

<entry>

<key></key>

<value></value>

</entry>

</job-data-map>

</job>

<trigger>

<!--
Trigger分为simple,cron,date-interval三种类型,一个trigger中只能指定一种类型-->

<simple>

<name></name>

<group></group>

<description></description>

<job-name></job-name>

<job-group></job-group>

<calendar-name></calendar-name>

<volatility></volatility>

<job-data-map>

<entry>

<key></key>

<value></value>

</entry>

</job-data-map>

<start-time></start-time>

<end-time></end-time>

<misfire-instruction></misfire-instruction>

<repeat-count></repeat-count>

<repeat-interval></repeat-interval>

</simple>

<cron>

<name></name>

<group></group>

<description></description>

<job-name></job-name>

<job-group></job-group>

<calendar-name></calendar-name>

<volatility></volatility>

<job-data-map>

<entry>

<key></key>

<value></value>

</entry>

</job-data-map>

<start-time></start-time>

<end-time></end-time>

<misfire-instruction></misfire-instruction>

<cron-expression></cron-expression>

<time-zone></time-zone>

</cron>

<date-interval>

<name></name>

<group></group>

<description></description>

<job-name></job-name>

<job-group></job-group>

<calendar-name></calendar-name>

<volatility></volatility>

<job-data-map>

<entry>

<key></key>

<value></value>

</entry>

</job-data-map>

<start-time></start-time>

<end-time></end-time>

<misfire-instruction></misfire-instruction>

<repeat-interval></repeat-interval>

<repeat-interval-unit></repeat-interval-unit>

</date-interval>

</trigger>

</schedule>

</job-scheduling-data>

代码清单7:quartz_jobs.xml示例

<?xmlversion="1.0"encoding="UTF-8"?>

<job-scheduling-dataxmlns="http://www.quartz-scheduler.org/xml/JobSchedulingData"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.quartz-scheduler.org/xml/JobSchedulingData
http://www.quartz-scheduler.org/xml/job_scheduling_data_1_8.xsd"

version="1.8">

<pre-processing-commands>

<delete-jobs-in-group>*</delete-jobs-in-group> <!--
clear all jobs in scheduler -->

<delete-triggers-in-group>*</delete-triggers-in-group><!--
clear all triggers in scheduler -->

</pre-processing-commands>

<processing-directives>

<overwrite-existing-data>true</overwrite-existing-data>

<ignore-duplicates>false</ignore-duplicates>

</processing-directives>

<schedule>

<job>

<name>helloQuartzJob</name>

<group>DEFAULT</group>

<description>简单的quartz使用</description>

<job-class>HelloQuartzJob</job-class>

<volatility>false</volatility>

<durability>true</durability>

<recover>false</recover>

</job>

<trigger>

<cron>

<name>trigger</name>

<group>DEFAULT</group>

<job-name>helloQuartzJob</job-name>

<job-group>DEFAULT</job-group>

<cron-expression>30/5
* * * * ?</cron-expression>

</cron>

</trigger>

</schedule>

</job-scheduling-data>

代码清单8:Quartz任务调度

public class HelloQuartzScheduling {

public static void main(String[] args)

throws SchedulerException, ParseException {

SchedulerFactory schedulerFactory = new StdSchedulerFactory();

Scheduler scheduler = schedulerFactory.getScheduler();

scheduler.start();

}

}

这里遇到个问题,提示错误:

Exception in thread "main" java.lang.NoClassDefFoundError: javax/transaction/UserTransaction

是由于缺少jta.jar,google出的结果是在quartz发行包的/lib中有此jar包,但是在1.8中没有找到。下载quartz 1.7中,也没有找到,因此,在网上搜一个jta.jar包放置过程classpath中,然后编译运行,ok.

时间: 2024-10-29 07:33:39

Quartz笔记(一)的相关文章

quartz笔记

首先网络上的很多教程经常有错(信息过载了),其主要原因是版本发生了变化,例如quartz1和2之间还是有不少差别的,导致查找资料的人浪费了不少时间.所以无论教程如何写,都建议读者首先学习官网的教程,如果有一些资料官网没有,例如扩展的东西或者和其他框架整合的东西,再去参考其他资料. 本文仅为我个人学习记录.建议重点参考官网:www.quartz-scheduler.org quartz版本:2.2.1 原生quartz: 基本思路: 通过工厂创建一个Scheduler 创建一个实现Job接口的实现

[Quartz笔记]玩转定时调度

简介 Quartz是什么? Quartz是一个特性丰富的.开源的作业调度框架.它可以集成到任何Java应用. 使用它,你可以非常轻松的实现定时任务的调度执行. Quartz的应用场景 场景1:提醒和告警 场景2:监听事务 场景3:定时作业 Quartz的安装 安装 1.可以直接在官网:http://www.quartz-scheduler.org/ 下载jar包. 2.如果使用maven,可以在pom.xml中添加以下依赖jar包: <dependency> <groupId>or

Quartz.NET 2.0 学习笔记(1) :Quartz.NET简介

转自:http://www.cnblogs.com/lzrabbit/archive/2012/04/13/2447609.html Quartz.NET 项目地址 http://quartznet.sourceforge.net/ Quartz.NET 2.0 学习笔记(1) :Quartz.NET简介 Quartz.NET 2.0 学习笔记(2) :和1.0的几点不同 Quartz.NET 2.0 学习笔记(3) :通过配置文件实现任务调度 Quartz.NET 2.0 学习笔记(4) :c

Quartz学习笔记

什么是job schedule system? job schedule system是负责在预定义的时间执行或者通知某个应用组件的系统.举个例子来说,比如在每周一早上9:30发送email通知客户最新的业务情况. java.util.Timer和java.util.TimerTask Timer和TimerTask是可以完成job schedule的两个jdk提供的类,不过这不能称为一个system.Timer和TimerTask是很简单的,不直接支持持久化任务,线程池和类似日历(calend

Quartz.net 2.x 学习笔记03-使用反射加载定时任务

将定时任务信息存储在XML文件中,使用反射加载定时任务 首先新建一个MVC的空站点,使用NuGet添加对Quartz.net和Common.Logging.Log4Net1213的引用,同时使用NuGet管理器控制台执行命令更新log4net,PM> update-package log4net 接着在解决方案中添加一个类库Library项目 类库项目也添加对Quartz.net的引用 下面可以编写代码了,在Library类库中添加一个JobBase类,3个Job类,和一个Job管理类(假设分别

Quartz.Net学习笔记(2)-简介

一.Quartz.Net是什么 1.来源 Quartz.Net是一个开源的作业调度框架: 2.下载地址 官网地址:http://www.quartz-scheduler.net/documentation/index.html 源码地址:https://sourceforge.net/projects/quartznet/ 二.Quartz.Net能干什么 定时轮询数据库同步,定时邮件通知 三.Quartz.Net中的设计模式 1.Builder模式 所有关键组件都由Builder模式来构建<B

QuartZ .Net 学习笔记一: 源码下载与查看

最近因为工作需要研究一下QuartZ .net , 之前也用过不过但没有深入了解,  现想深入研究一下 网上相关QuartZ .net 的文章不少, 但大部分都是源于张善友的博客http://www.cnblogs.com/shanyou/category/102991.html. 写的很全面,看了之后受益匪浅. 在这里将学习的一些收获记录一下, 方便将来查看 Quartz.net 是Quartz的移植版本, 历史来源不做过多介绍 网上几乎所有相关介绍都是写到http://quartznet.s

Quartz.NET笔记(三) More About Jobs &amp; JobDetails

如你所见,Job相当容易实现.这里只是介绍有关Jobs本质, IJob接口的Execute(..)方法以及JobDetails中需要理解的内容. 在所实现的类成为真正的“Job”时,期望任务所具有的各种属性需要通知给Quartz.通过JobDetail类可以完成这个工作,这个类在前面的章节中曾简短提及过.现在,我们花一些时间来讨论Quartz中Jobs的本质和Job实例的生命周期.首先让我们回顾一下第一课中所看到的代码片断: Using Quartz.NET 1 // define the jo

Quartz.NET笔记(一) 概述

配置 有三种配置方式: 1.编码方式: scheduler factory提供的NameValueCollection参数 2.使用标准的 youapp.exe.config配置文件中的quartz-element 3.应用程序根目录中的quartz.config配置文件 注意:VS中要将配置文件设置为“Copy always” 一个简单的例子: Program.cs 1 using System; 2 using System.Threading; 3 4 using Quartz; 5 us