3.1、Job
打开Job
源码,里面其实就是一个包含执行方法void execute(JobExecutionContext context)
的接口,开发者只需实现接口来定义具体任务即可!
public interface Job { void execute(JobExecutionContext context) throws JobExecutionException; }
JobExecutionContext
类封装了获取上下文的各种信息,Job
运行时的信息也保存在 JobDataMap
实例中!
例如,我想要获取在上文初始化时使用到的usingJobData("jobData", "test")
参数,可以通过如下方式进行获取!
@Override public void execute(JobExecutionContext context) throws JobExecutionException { //从context中获取instName,groupName以及dataMap String jobName = context.getJobDetail().getKey().getName(); String groupName = context.getJobDetail().getKey().getGroup(); JobDataMap dataMap = context.getJobDetail().getJobDataMap(); //从dataMap中获取myDescription,myValue以及myArray String value = dataMap.getString("jobData"); System.out.println("jobName:" + jobName + ",groupName:" + groupName + ",jobData:" + value); }
输出结果:
jobName:myJob,groupName:myJobGroup,jobData:test
3.2、Trigger
Trigger
主要用于描述Job
执行的时间触发规则,最常用的有SimpleTrigger
和CronTrigger
两个实现类型。
- SimpleTrigger:主要处理一些简单的调度规则,例如触发一次或者以固定时间间隔周期执行
- CronTrigger:调度处理更加灵活,可以通过
Cron
表达式定义出各种复杂时间规则的调度方案,例如每早晨9:00执行,周一、周三、周五下午5:00执行等;
3.2.1、SimpleTrigger
用SimpleTrigger
实现每2秒钟执行一次任务为例,代码如下:
public static void main(String[] args) throws SchedulerException { //构建一个JobDetail实例... // 构建一个Trigger,指定Trigger名称和组,规定该Job立即执行,且两秒钟重复执行一次 SimpleTrigger trigger = TriggerBuilder.newTrigger() .startNow() // 执行的时机,立即执行 .withIdentity("myTrigger", "myTriggerGroup") // 不是必须的 .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(2).repeatForever()).build(); // 让scheduler开始调度这个job, 按trigger指定的计划 scheduler.scheduleJob(job, trigger); }
运行结果:
2020-12-03 16:55:53 2020-12-03 16:55:55 2020-12-03 16:55:57 ......
其中最关键的就是withSchedule()
这个方法,通过SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever()
来构建了一个简单的SimpleTrigger
类型的任务调度规则,从而实现任务调度!
3.2.2、CronTrigger
如开始介绍的例子一样,里面使用正是CronTrigger
类型的调度规则!
public static void main(String[] args) throws SchedulerException { //构建一个JobDetail实例... // 新建一个Trigger, 表示JobDetail的调度计划, 这里的cron表达式是 每5秒执行一次 Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("myTrigger", "myTriggerGroup") .startNow() // 立即执行 .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")) .build(); // 让scheduler开始调度这个job, 按trigger指定的计划 scheduler.scheduleJob(job, trigger); }
运行结果:
2020-12-03 17:09:10 2020-12-03 17:09:15 2020-12-03 17:09:20 ......
CronTrigger
相比SimpleTrigger
,在配置调度规则方面,使用cron
表达式更加灵活!
3.2.3、Cron 表达式详解
Quartz 的 Cron 表达式,具体配置规则可以参考如下:
.---------------------- seconds(0 - 59) | .------------------- minute (0 - 59) | | .---------------- hour (0 - 23) | | | .------------- day of month (1 - 31) | | | | .---------- month (1 - 12) | | | | | .------- Day-of-Week (1 - 7) | | | | | | .---- year (1970 - 2099) ... | | | | | | | * * * * * ? *
具体样例如下:
在 cron 表达式中不区分大小写,更多配置和使用操作可以参考这里。
还可以在线解析cron
表达式进行测试。
3.3、监听器(选用)
quartz 除了提供能正常调度任务的功能之外,还提供了监听器功能!
所谓监听器,其实你可以把它理解为类似Spring Aop
的功能,可以对全局或者局部实现监听!
监听器应用,在实际项目中并不常用,但是在某些业务场景下,可以发挥一定的作用,例如:你想在任务处理完成之后,去发送邮件或者发短信进行通知,但是你又不想改以前的代码,这个时候就可以在监听器里面完成改项任务!
quartz 监听器主要分三大类:
- SchedulerListener:任务调度监听器
- TriggerListener:任务触发监听器
- JobListener:任务执行监听器
3.3.1、SchedulerListener
SchedulerListener
监听器,主要对任务调度Scheduler
生命周期中关键节点进行监听,它只能全局进行监听,简单示例如下:
public class SimpleSchedulerListener implements SchedulerListener { @Override public void jobScheduled(Trigger trigger) { System.out.println("任务被部署时被执行"); } @Override public void jobUnscheduled(TriggerKey triggerKey) { System.out.println("任务被卸载时被执行"); } @Override public void triggerFinalized(Trigger trigger) { System.out.println("任务完成了它的使命,光荣退休时被执行"); } @Override public void triggerPaused(TriggerKey triggerKey) { System.out.println(triggerKey + "(一个触发器)被暂停时被执行"); } @Override public void triggersPaused(String triggerGroup) { System.out.println(triggerGroup + "所在组的全部触发器被停止时被执行"); } @Override public void triggerResumed(TriggerKey triggerKey) { System.out.println(triggerKey + "(一个触发器)被恢复时被执行"); } @Override public void triggersResumed(String triggerGroup) { System.out.println(triggerGroup + "所在组的全部触发器被回复时被执行"); } @Override public void jobAdded(JobDetail jobDetail) { System.out.println("一个JobDetail被动态添加进来"); } @Override public void jobDeleted(JobKey jobKey) { System.out.println(jobKey + "被删除时被执行"); } @Override public void jobPaused(JobKey jobKey) { System.out.println(jobKey + "被暂停时被执行"); } @Override public void jobsPaused(String jobGroup) { System.out.println(jobGroup + "(一组任务)被暂停时被执行"); } @Override public void jobResumed(JobKey jobKey) { System.out.println(jobKey + "被恢复时被执行"); } @Override public void jobsResumed(String jobGroup) { System.out.println(jobGroup + "(一组任务)被恢复时被执行"); } @Override public void schedulerError(String msg, SchedulerException cause) { System.out.println("出现异常" + msg + "时被执行"); cause.printStackTrace(); } @Override public void schedulerInStandbyMode() { System.out.println("scheduler被设为standBy等候模式时被执行"); } @Override public void schedulerStarted() { System.out.println("scheduler启动时被执行"); } @Override public void schedulerStarting() { System.out.println("scheduler正在启动时被执行"); } @Override public void schedulerShutdown() { System.out.println("scheduler关闭时被执行"); } @Override public void schedulerShuttingdown() { System.out.println("scheduler正在关闭时被执行"); } @Override public void schedulingDataCleared() { System.out.println("scheduler中所有数据包括jobs, triggers和calendars都被清空时被执行"); } }
需要在任务调度器启动前,将SimpleSchedulerListener
注册到Scheduler
容器中!
// 创建一个Scheduler Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); //添加SchedulerListener监听器 scheduler.getListenerManager().addSchedulerListener(new SimpleSchedulerListener()); // 启动Scheduler scheduler.start();
运行main
方法,输出结果如下:
scheduler正在启动时被执行 scheduler启动时被执行 一个JobDetail被动态添加进来 任务被部署时被执行 2020-12-10 17:27:10 ....