quartz的任务调度功能比JDK自带的Timer强大得多,有必要学习并致用,在此记录一下...
quartz的jar包在官网可以下载到,百度/谷歌:quartz
maven依赖(可以在maven repository找到绝大多数jar的maven依赖):
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.2</version> </dependency>
Job接口:只有一个execute方法,类似TimerTask的run方法,里面编写业务逻辑,调用完成后job对象会被销毁
jobDetail是一个包含多个属性的job细节类,用来设置jobClass、name、group、jobDataMap、
其中name和group都是某一个job的标识,JobKey类就包含了这2个属性,
jobClass属性对应我们自己创建的实现了job接口的类,用jobDetail的getKey方法来获取。jobDataMap是Job和Trigger都有的一个属性,用来存放属性,比如持有别的类的引用,我们需要
把该对象存入HelloJob对象的jobDataMap中,不能直接当作HelloJob.class的属性。
JobExecutionContext:当schedule调用一个job,就会把JobExecutionContext传递到该job的execute方法中,
方便我们获取quartz运行时环境和该job本身的属性,比如获取jobDataMap。context.getJobDetail().getKey();
context.getJobDetail().getJobDataMap();
context.getTrigger().getKey();
usingJobData(key, value);最常用的触发器:SimpleTrigger(类似Timer)、CronTrigger
触发器也有name和group属性,以及存放其它自定义属性的jobDataMaptrigger与job的关系是:n对1,即同一个job可以被多个触发器使用
cronTrigger是我们使用quartz的主要原因,我们可以传一个表达式给触发器,该表达式与linux的crontab一样,
它提供了基于日历的、更精细的时间安排,具备jdk自带的timer无法实现的功能。
Cron表达式是由7个表达式组成的字符串
格式:秒 分 时 日 月 周 年
注意:
1.LW一起使用表示最后一个工作日
2.周字段不区分大小写,MON和mon一样
3.利用工具在线生成cron表达式,百度cron在线生成即可Schedule 所有调度器实例都由工厂模式产生,比如StdScheduleFactory(常用)和DirectScheduleFactory
scheduler的主要函数:
Date scheduleJob() // 绑定触发器和任务void start() // 启动调度器线程
void standby() // 挂起调度器线程
void shutdown() // 关闭调度器线程
3个核心组件的关系图
以下是基于HelloJob绑定到SimpleTrigger和CronTrigger的2个例子:
package quartzTest;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
* writer: holien
* Time: 2017-07-29 21:55
* Intent: 实现了Job接口的job类,业务逻辑写在execute方法里
*/
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("job has executed");
}
}
package quartzTest;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.util.Date;
/**
* writer: holien
* Time: 2017-07-29 22:07
* Intent: 使用simpleTrigger的示例
*/
public class SimpleTriggerTest {
public static void main(String[] args) throws Exception {
JobKey jobKey1 = new JobKey("job1", "group1");
JobDetail jobDetail = JobBuilder
.newJob(HelloJob.class)
.withIdentity(jobKey1)
.build();
// 创建触发器的开始时间和结束时间,该触发器的执行时间为6秒
Date startTime = new Date();
Date endTime = new Date();
endTime.setTime(endTime.getTime() + 6000);
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1")
.startAt(startTime) //触发时间
.endAt(endTime) //结束时间
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2) //每2秒执行一次
.withRepeatCount(5)) //由于执行时间只有6秒,所以只会执行3次
.build();
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start(); //启动scheduler调度器线程
scheduler.scheduleJob(jobDetail, trigger);
// scheduler.shutdown(true); // true:等待任务执行完再关闭;false:直接关闭
}
}
package quartzTest;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.KeyMatcher;
/**
* writer: holien
* Time: 2017-07-29 21:17
* Intent: 使用cronTrigger的示例
*/
public class CronTriggerTest {
public static void main(String[] args) throws Exception {
JobKey jobKey1 = new JobKey("job1", "group1");
JobDetail jobDetail = JobBuilder
.newJob(HelloJob.class)
.withIdentity(jobKey1)
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1")
.withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?"))
.build();
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(jobDetail, trigger);
// 添加监听器
scheduler.getListenerManager().addJobListener(
new HelloJobListener(), KeyMatcher.keyEquals(jobKey1));
}
}
Job、Trigger、Schedule都有对应的监听器,以下用Job的监听器来展示一下
jobListener监听器用来监听一个job,提供了jobToBeExecuted、jobExecutionVetoed、jobWasExecuted3个方法,分别对应job执行前、Job即将被执行,但又被 TriggerListener否决时执行、job执行后。
还有一个比较重要的,设置监听器的名字,也就是我们要重写getName方法,返回一个自定义的名称。
以下是用来监听HelloJob的监听器类:
package quartzTest;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;
/**
* writer: holien
* Time: 2017-07-30 12:00
* Intent:
*/
public class HelloJobListener implements JobListener {
// 必须为监听器设置一个名字,否则会报错
@Override
public String getName() {
return "HelloJobListener";
}
// 每次job执行之前执行此方法
@Override
public void jobToBeExecuted(JobExecutionContext jobExecutionContext) {
System.out.println("job is to be executed");
}
// 每次Job即将被执行,但又被TriggerListener否决时执行
@Override
public void jobExecutionVetoed(JobExecutionContext jobExecutionContext) {
System.out.println("job is canceled");
}
// 每次job执行之后执行此方法
@Override
public void jobWasExecuted(JobExecutionContext jobExecutionContext, JobExecutionException e) {
System.out.println("job has been canceled");
}
}
默认的quartz.properties
文件位于org.quartz包下,我们可以复制一份,放在项目的根目录下,再根据自己的需要修改它里面的属性,
这样项目运行就会优先加载我们自定义的quartz.properties文件,否则加载quartz jar包中自带的。
instanceName:给调度器命名,可以按照功能来命名,比如我们一个quartz集群是为一个功能服务的,
那么调度器的name根据该功能命名,多个调度器取一样的名称
instanceId:指定调度器的唯一id,可以设置AUTO自动生成
此文件还可以配置线程池的信息,还有插件信息