一、简介

1.概述

OpenSymphony所提供的Quartz自2001年发布版本以来已经被众多项目作为任务调度的解决方案,Quartz在提供巨大灵活性的同时并未牺牲其简单性,它所提供的强大功能使你可以应付绝大多数的调度需求。是开源任务调度框架中的翘首,它提供了强大任务调度机制,难能可贵的是它同时保持了使用的简单性。Quartz
允许开发人员灵活地定义触发器的调度时间表,并可以对触发器和任务进行关联映射。

2.作用

  • 应用程序需要在给定时间执行任务,或者系统有连续维护作业
  • 系统维护:调度工作给数据库的内容,每个工作日(节假日除外平日)在11:30 PM转储到一个XML文件中。
  • 在应用程序内提供提醒服务 例如:定时备份数据库

二、Quartz体系结构

核心概念

任务

Job:是一个接口,开发者实现该接口定义运行任务
JobDetail:Quartz在每次执行Job时,都重新创建一个Job实例,所以它不直接接受一个Job的实例,相反它接收一个Job实现 类(实现类的Class对象),以便运行时通过newInstance()的反射机制实例化Job。因此需要通过一个类来描述Job的实现类及其它相关的静态信息,如Job名字、描 述、关联监听器等信息,JobDetail承担了这一角色

Trigger

定义:是一个类,描述触发Job执行的时间触发规则,主要有SimpleTrigger和CronTrigger这两个子类
SimpleTrigger:当仅需触发一次或者以固定时间间隔周期执行
CronTrigger:可以通过Cron表达式定义出各种复杂时间规则的调度方案:如每早晨9:00执行,周一、周三、周五下午5:00执行等
Calendar:它是一些日历特定时间点的集合,一个Trigger可以和多个Calendar关联,以便排除或 包含某些时间点。

调度器

Scheduler:代表一个Quartz的独立运行容器,Trigger和JobDetail可以注册到Scheduler中,两者在 Scheduler中拥有各自的组及名称,组及名称是Scheduler查找定位容器中某一对象的依据,Trigger的组及名称必须唯 一,JobDetail的组和名称也必须唯一。Scheduler定义了多个接口方法, 允许外部通过组及名称访问和控制容器中Trigger和JobDetail。一个Job可以对应 多个Trigger,但一个Trigger只能对应一个Job。

Java调度机制 java任务调度quartz_时间间隔


描述了Scheduler的内部组件结构,SchedulerContext提供Scheduler全局可见的上下文信息,每一个任务都对应一个JobDataMap,虚线表达的JobDataMap表示对应有状态的任务。一个Scheduler可以拥有多个Triger组和多个JobDetail组,注册Trigger和JobDetail时,如果不显式指定所属的 组,Scheduler将放入到默认组中,默认组的组名为Scheduler.DEFAULT_GROUP。组名和名称组成了对象的全名,同一类型对象的 全名不能相同。

Scheduler本身就是一个容器,它维护着Quartz的各种组件并实施调度的规则。Scheduler还拥有一个线程池,线程池为任务提供执 行线程——这比执行任务时简单地创建一个新线程要拥有更高的效率,同时通过共享节约资源的占用。通过线程池组件的支持,对于繁忙度高、压力大的任务调 度,Quartz将可以提供良好的伸缩性。

三、案例

1.SimpleTrigger

构造函数
SimpleTrigger(String name, String group):通过该构造函数指定Trigger所属组和名称;
SimpleTrigger(String name, String group, Date startTime):除指定Trigger所属组和名称外,还可以指定触发的开发时间;
SimpleTrigger(String name, String group, Date startTime, Date endTime, int repeatCount, long repeatInterval):除指定以上信息外,还可以指定结束时间、重复执行次数、时间间隔等参数;
SimpleTrigger(String name, String group, String jobName, String jobGroup, Date startTime, Date endTime, int repeatCount, long repeatInterval):这是最复杂的一个构造函数,在指定触发参数的同时,还通过jobGroup和jobName,让该Trigger和 Scheduler中的某个任务关联起来。
环境搭建

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.0</version>
</dependency>
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz-jobs</artifactId>
    <version>2.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.21</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.21</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.9</version>
    <scope>test</scope>
</dependency>

2.CronTrigger

CronTrigger 能够提供比 SimpleTrigger 更有具体实际意义的调度方案,调度规则基于 Cron 表达式,CronTrigger 支持日历相关的重复时间间隔(比如每月第一个周一执行),而不是简单的周期时间间隔。因此,相对于SimpleTrigger而 言,CronTrigger在使用上也要复杂一些。

Cron表达式
Quartz使用类似于Linux下的Cron表达式定义时间规则,
Cron表达式由6或7个由空格分隔的时间字段组成,如表1所示: X X X X X X [X]

位置

字段范围

范围

允许的特使字符

1


0~59

* /

2

分钟

0~59

* /

3

小时

0~23

* /

4

月份中的哪一天

1~31

* / ? L W

5

月份

1~12 或 JAN~DEC

* /

6 星期几

1~7 或 SUN~SAT

* / ? L #

7

年份

1970~2099

* /

Cron表达式的时间字段除允许设置数值外,还可使用一些特殊的字符,提供列表、范围、通配符等功能
星号(*):可用在所有字段中,表示对应时间域的每一个时刻,例如,在分钟字段时,表示“每分钟”;
问号(?):该字符只在日期和星期字段中使用,它通常指定为“无意义的值”,相当于点位符;
减号(-):表达一个范围,如在小时字段中使用“10-12”,则表示从10到12点,即10,11,12;
逗号(,):表达一个列表值,如在星期字段中使用“MON,WED,FRI”,则表示星期一,星期三和星期五;
斜杠(/):x/y表达一个等步长序列,x为起始值,y为增量步长值。如在秒字段中使用0/15,则表示为0,15,30和45秒,而5/15在分钟字段中表示5,20,35,50,你也可以使用/y,它等同于0/y;
L:该字符只在日期和星期字段中使用,代表“Last”的意思,但它在两个字段中意思不同。L在日期字段中,表示这个月份的最后一天,如一月的 31号,非闰年二月的28号;如果L用在星期中,则表示星期六,等同于7。但是,如果L出现在星期字段里,而且在前面有一个数值X,则表示“这个月的最后 X天”,例如,6L表示该月的最后星期五;
W:该字符只能出现在日期字段里,是对前导日期的修饰,表示离该日期最近的工作日。例如15W表示离该月15号最近的工作日,如果该月15号是星 期六,则匹配14号星期五;如果15日是星期日,则匹配16号星期一;如果15号是星期二,那结果就是15号星期二。但必须注意关联的匹配日期不能够跨 月,如你指定1W,如果1号是星期六,结果匹配的是3号星期一,而非上个月最后的那天。W字符串只能指定单一日期,而不能指定日期范围;
LW组合:在日期字段可以组合使用LW,它的意思是当月的最后一个工作日;
井号(#):该字符只能在星期字段中使用,表示当月某个工作日。如6#3表示当月的第三个星期五(6表示星期五,#3表示当前的第三个),而4#5表示当月的第五个星期三,假设当月没有第五个星期三,忽略不触发;
C:该字符只在日期和星期字段中使用,代表“Calendar”的意思。它的意思是计划所关联的日期,如果日期没有被关联,则相当于日历中所有日期。例如5C在日期字段中就相当于日历5日以后的第一天。1C在星期字段中相当于星期日后的第一天。

3.Calendar

Quartz 提供了一个Calendar对象,(注意不是java.util.Calendar),并用它关联触发器,在指定的时间内不执行任务,例如:我们可以在每一个周末创建一个trigger对象,但是不包含法定的节假日。

以下是Quartz给我们提供的日历管理控件

名称

含义

AnnualCalendar

This implementation of the Calendar excludes a set of days of the year.

BaseCalendar

This implementation of the Calendar may be used (you don’t have to) as a base class for more sophisticated one’s.

CronCalendar

This implementation of the Calendar excludes the set of times expressed by a given CronExpression.

DailyCalendar

This implementation of the Calendar excludes (or includes - see below) a specified time range each day.

HolidayCalendar

This implementation of the Calendar stores a list of holidays (full days that are excluded from scheduling).

MonthlyCalendar

This implementation of the Calendar excludes a set of days of the month.

WeeklyCalendar

This implementation of the Calendar excludes a set of days of the week.

AnnualCalendar案例,避开五一,国庆执行

public static void main(String[] args) throws SchedulerException, InterruptedException {
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();

Calendar calendar = new GregorianCalendar();
	calendar.set(Calendar.MONTH, 4);
	calendar.set(Calendar.DATE, 1);
	AnnualCalendar holidays = new AnnualCalendar();
	
	holidays.setDayExcluded(calendar, true);
	
	Calendar calendar2 = new GregorianCalendar();
	calendar2.set(Calendar.MONTH, 9);
	calendar2.set(Calendar.DATE, 1);
	
	holidays.setDayExcluded(calendar2, true);
	
	
	//不触发trigger触发器
	scheduler.addCalendar("myHolidays", holidays, false, false);
	Trigger trigger = TriggerBuilder.newTrigger().
			withIdentity("myTrigger", "group").
			startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3)
					.repeatForever()).modifiedByCalendar("myHolidays").build();
	JobDetail jobDetail = JobBuilder.newJob(MyJob.class).build();
	scheduler.scheduleJob(jobDetail,trigger);
	
	scheduler.start();	
}

CronCalendar案例

public static void main(String[] args) throws SchedulerException, InterruptedException, ParseException {
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();

///在早8点-晚5点触发,其他时间暂停。
	CronCalendar holidays = new CronCalendar("* * 0-7,18-23 ? * * ");

	//不触发trigger触发器
	scheduler.addCalendar("myHolidays", holidays, false, false);
	Trigger trigger = TriggerBuilder.newTrigger().
			withIdentity("myTrigger", "group").
			startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3)
					.repeatForever()).modifiedByCalendar("myHolidays").build();
	JobDetail jobDetail = JobBuilder.newJob(MyJob.class).build();
	scheduler.scheduleJob(jobDetail,trigger);	
	scheduler.start();	
}

四、整合spring

1.Quartz Schduler配置作业

A:使用 MethodInvokingJobDetailFactoryBean 这种方式在你想要调用特定 bean 的一个方法的时候很是方便,比另一种方法要简单的多。
B:使用 JobDetailFactoryBean 如果你需要更高级的设置,需要给作业传递数据,想更加灵活的话就使用这种方式.
jobClass 关联到一个继承自 QuartzJobBean 的类,它实现了 Quartz 作业接口。调用到这个作业的时候,它的 executeInternal 将被执行。

2.配置 Quartz 调度时要使用到的触发器

触发器用来定义调度器何时将会执行你的调度任务的那个时间。有两种可能的触发器类型:
A:简单触发器,使用 SimpleTriggerFactoryBean 你可以定义作业的启动时间、触发器之间的延迟时间以及 repeatInterval(频率)。
B:计划触发器,使用 CronTriggerFactoryBean 这种类型更加灵活,允许你针对特定实例选择计划方案以及将来要执行的频率。

3.配置创建定配置 Quartz 调度器的 SchedulerFactoryBean

SchedulerFactoryBean 将 jobDetails 和 triggers 整合在一起以配置 Quartz 调度器。