项目地址:
https://github.com/yuleiqq/quartz_example/tree/master/quartz_study
Quartz 一些关键接口的API 如下:
- Scheduler : 主要用来交互调度器的api
- Job : 希望由调度器执行的组件实现的接口,比如上篇博客当中的HelloJob.java 。用户定义具体执行的任务.
- JobDetail :用来定义Job的实例
- Trigger : 一个组件,用来定义一个Job 如何 被调度器执行.
- JobBuilder : 用于定义/构建JobDetail实例,该实例定义作业的实例
- TriggerBuilder : 用于定义/构建触发器实例
通过SchedulerFactory和调用它的shutdown()方法,调度器的生命周期受到它的创建的限制。一旦创建了调度器接口,就可以使用它添加、删除和列出作业和触发器,以及执行其他与调度器相关的操作(例如暂停触发器)。然而,直到使用start()方法启动调度程序之前,它不会实际操作任何触发器(执行作业)。
Quartz提供了Domain Specific Language 表示法(即点(.) 方法调用)(或DSL,有时也称为“连贯接口”)的“builder”类。在上篇博客当中已经看到了. 下面来看下代码,里面包含了注释,就不细讲了。 对代码有疑问的,可以阅读代码之后的描述说明之后,再反过来看看代码内容,会有不一样的收获.
代码运行之前,首先更改下线程数
定义一个Job ,需要事先Job 接口,里面只有一个方法,可以子在这个方法里定义项目运行的业务逻辑.
package com.example02;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
/**
* @author : yulei
* @data : 2020/1/16 8:30
* @Version : 1.0
*
* 定义一个简单的任务(Job),该任务会在调度器(Scheduler)给其绑定触发器(Trigger)后执行
**/
public class SimpleJob implements Job {
private static Logger log = LoggerFactory.getLogger(SimpleJob.class);
public void execute(JobExecutionContext context) throws JobExecutionException {
JobKey jobKey = context.getJobDetail().getKey();
log.info("SimpleJob says "+ jobKey +" executing at " +new Date());
}
}
运行的主类,包含实例化Job ,定义触发器等.
package com.example02;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.TriggerBuilder.newTrigger;
/**
* @author : yulei
* @data : 2020/1/16 8:36
* @Version : 1.0
*
* 这个示例将演示使用简单触发器实现Quartz的所有基本调度功能
**/
public class SimpleTriggerExample {
Logger log = LoggerFactory.getLogger(SimpleTriggerExample.class);
public void run () throws Exception {
log.info("------- Initializing -------------------");
// 实例化调度器
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler();
log.info("------- Initialization Complete --------");
log.info("------- Scheduling Jobs ----------------");
//可以在调用sched.start() 之前 调用jobs
//定义任务的执行时间
Date startTime = DateBuilder.nextGivenSecondDate(null, 15);
/** job1**/
//job1 只会执行一次
JobDetail job = newJob(SimpleJob.class).withIdentity("job1", "group1").build();
//定义一个触发器
SimpleTrigger trigger = (SimpleTrigger) newTrigger().withIdentity("trigger1", "group1").startAt(startTime).build();
//使用调度器将job1 和 trigger1 绑定起来,并运行 .
Date ft = sched.scheduleJob(job, trigger);
log.info(job.getKey() + " will run at: " + ft + " and repeat: " + trigger.getRepeatCount() + " times, every "
+ trigger.getRepeatInterval() / 1000 + " seconds");
/** job2**/
//job2 和job1 一样,归属在同一个组中
job = newJob(SimpleJob.class).withIdentity("job2", "group1").build();
trigger = (SimpleTrigger) newTrigger().withIdentity("trigger2", "group1").startAt(startTime).build();
ft = sched.scheduleJob(job, trigger);
log.info(job.getKey() + " will run at: " + ft + " and repeat: " + trigger.getRepeatCount() + " times, every "
+ trigger.getRepeatInterval() / 1000 + " seconds");
/***job3***/
//运行11次 (1次立即运行;之后,每个10秒运行一次,共10次)
job = newJob(SimpleJob.class).withIdentity("job3", "group1").build();
trigger = newTrigger().withIdentity("trigger3", "group1").startAt(startTime)
.withSchedule(simpleSchedule().withIntervalInSeconds(10).withRepeatCount(10)).build();
ft = sched.scheduleJob(job, trigger);
log.info(job.getKey() + " will run at: " + ft + " and repeat: " + trigger.getRepeatCount() + " times, every "
+ trigger.getRepeatInterval() / 1000 + " seconds");
// 所有的任务已经被添加到调度器,但是任务都不会运行,直到调用start 方法之后.
sched.start();
// //在sched.start() 之后,jobs 仍然可以被调用.
// job = newJob(SimpleJob.class).withIdentity("job4", "group1").build();
// trigger = newTrigger().withIdentity("trigger4", "group1").startAt(startTime)
// .withSchedule(simpleSchedule().withIntervalInMinutes(5).withRepeatCount(20)).build();
//
// ft = sched.scheduleJob(job, trigger);
// log.info(job.getKey() + " will run at: " + ft + " and repeat: " + trigger.getRepeatCount() + " times, every "
// + trigger.getRepeatInterval() / 1000 + " seconds");
//
// //job 也可以立即执行,不用触发器
// job = newJob(SimpleJob.class).withIdentity("job5", "group1").storeDurably().build();
// log.info("'Manually' triggering job5...");
// sched.addJob(job, true);
//
// //job可以被再度调用
// log.info("------- Rescheduling... --------------------");
// trigger = newTrigger().withIdentity("trigger3", "group1").startAt(startTime)
// .withSchedule(simpleSchedule().withIntervalInMinutes(5).withRepeatCount(20)).build();
// ft = sched.rescheduleJob(trigger.getKey(), trigger);
// log.info("job3 rescheduled to run at: " + ft);
}
public static void main(String[] args) throws Exception {
SimpleTriggerExample example = new SimpleTriggerExample();
example.run();
}
}
运行效果如下:
[INFO] 16 一月 09:53:24.764 上午 main [org.quartz.impl.StdSchedulerFactory]
Quartz scheduler 'MyScheduler' initialized from default resource file in Quartz package: 'quartz.properties'
[INFO] 16 一月 09:53:24.764 上午 main [org.quartz.impl.StdSchedulerFactory]
Quartz scheduler version: 2.3.0
[INFO] 16 一月 09:53:24.764 上午 main [com.example02.SimpleTriggerExample]
------- Initialization Complete --------
[INFO] 16 一月 09:53:24.764 上午 main [com.example02.SimpleTriggerExample]
------- Scheduling Jobs ----------------
[INFO] 16 一月 09:53:24.779 上午 main [com.example02.SimpleTriggerExample]
group1.job1 will run at: Thu Jan 16 09:53:30 CST 2020 and repeat: 0 times, every 0 seconds
[INFO] 16 一月 09:53:24.780 上午 main [com.example02.SimpleTriggerExample]
group1.job2 will run at: Thu Jan 16 09:53:30 CST 2020 and repeat: 0 times, every 0 seconds
[INFO] 16 一月 09:53:24.780 上午 main [com.example02.SimpleTriggerExample]
group1.job3 will run at: Thu Jan 16 09:53:30 CST 2020 and repeat: 10 times, every 10 seconds
[INFO] 16 一月 09:53:24.780 上午 main [org.quartz.core.QuartzScheduler]
Scheduler MyScheduler_$_NON_CLUSTERED started.
[INFO] 16 一月 09:53:30.006 上午 MyScheduler_Worker-1 [com.example02.SimpleJob]
SimpleJob says group1.job1 executing at Thu Jan 16 09:53:30 CST 2020
[INFO] 16 一月 09:53:30.006 上午 MyScheduler_Worker-2 [com.example02.SimpleJob]
SimpleJob says group1.job2 executing at Thu Jan 16 09:53:30 CST 2020
[INFO] 16 一月 09:53:30.007 上午 MyScheduler_Worker-3 [com.example02.SimpleJob]
SimpleJob says group1.job3 executing at Thu Jan 16 09:53:30 CST 2020
[INFO] 16 一月 09:53:40.000 上午 MyScheduler_Worker-4 [com.example02.SimpleJob]
SimpleJob says group1.job3 executing at Thu Jan 16 09:53:40 CST 2020
[INFO] 16 一月 09:53:50.001 上午 MyScheduler_Worker-5 [com.example02.SimpleJob]
SimpleJob says group1.job3 executing at Thu Jan 16 09:53:50 CST 2020
[INFO] 16 一月 09:54:00.000 上午 MyScheduler_Worker-6 [com.example02.SimpleJob]
SimpleJob says group1.job3 executing at Thu Jan 16 09:54:00 CST 2020
[INFO] 16 一月 09:54:10.002 上午 MyScheduler_Worker-7 [com.example02.SimpleJob]
SimpleJob says group1.job3 executing at Thu Jan 16 09:54:10 CST 2020
[INFO] 16 一月 09:54:20.001 上午 MyScheduler_Worker-8 [com.example02.SimpleJob]
SimpleJob says group1.job3 executing at Thu Jan 16 09:54:20 CST 2020
[INFO] 16 一月 09:54:30.002 上午 MyScheduler_Worker-9 [com.example02.SimpleJob]
SimpleJob says group1.job3 executing at Thu Jan 16 09:54:30 CST 2020
[INFO] 16 一月 09:54:40.001 上午 MyScheduler_Worker-10 [com.example02.SimpleJob]
SimpleJob says group1.job3 executing at Thu Jan 16 09:54:40 CST 2020
[INFO] 16 一月 09:54:50.008 上午 MyScheduler_Worker-11 [com.example02.SimpleJob]
SimpleJob says group1.job3 executing at Thu Jan 16 09:54:50 CST 2020
[INFO] 16 一月 09:55:00.001 上午 MyScheduler_Worker-12 [com.example02.SimpleJob]
SimpleJob says group1.job3 executing at Thu Jan 16 09:55:00 CST 2020
[INFO] 16 一月 09:55:10.000 上午 MyScheduler_Worker-13 [com.example02.SimpleJob]
SimpleJob says group1.job3 executing at Thu Jan 16 09:55:10 CST 2020
代码里的注释感兴趣的可以自行放开,运行试试。
观看上面的代码,我们可以发现,Quartz 提供一个Job 接口用于自定义任务,实现我们的业务逻辑。提供Trigger 定义控制任务的执行. JobDetail 实例化Job . 还有一些builder 类 ,也是上文所说的DSL 语法,我们可以通过如下方式进行引入:
import static org.quartz.JobBuilder.*;
import static org.quartz.SimpleScheduleBuilder.*;
import static org.quartz.CronScheduleBuilder.*;
import static org.quartz.CalendarIntervalScheduleBuilder.*;
import static org.quartz.TriggerBuilder.*;
import static org.quartz.DateBuilder.*;
各种“ScheduleBuilder”类都有与定义不同类型的调度相关的方法。
DateBuilder类包含各种方法,可以方便地构造java.util。特定时间点的日期实例(例如表示下一个偶数小时的日期—或者换句话说,如果当前是9:43:27,则为10:00:00)。
如下是官网对Job 和JobDetail 的一些介绍 :
当作业的触发器触发时(稍后详细讨论),调度程序的一个工作线程将调用execute(..)方法。传递给这个方法的JobExecutionContext对象为作业实例提供关于其“运行时”环境的信息——执行它的调度程序的句柄、触发执行的触发器的句柄、作业的JobDetail对象,以及其他一些项。
JobDetail对象是由Quartz客户机(您的程序)在将作业添加到调度器时创建的。它包含作业的各种属性设置,以及JobDataMap,可用于存储作业类的给定实例的状态信息。它本质上是作业实例的定义,在下一课中将进一步详细讨论。
触发器对象用于触发作业的执行(或“触发”)。当您希望调度作业时,您实例化一个触发器并“调优”其属性以提供您希望的调度。触发器还可能有一个与之关联的JobDataMap——这对于将参数传递给特定于触发器触发的作业非常有用。Quartz有几种不同的触发类型,但最常用的是SimpleTrigger和CronTrigger。
如果您需要“一次性”执行(在给定的时间点只执行一次任务),或者需要在给定的时间点执行一个任务,并让它重复N次,并且在执行之间有T的延迟,那么SimpleTrigger非常方便。如果您希望基于类似日历的时间表(如“每周五中午”或“每月10日上午10点15分”)进行触发,CronTrigger是非常有用的。
为什么是Jobs和Trigger ?许多作业调度器没有作业和触发器的独立概念。有些人将“作业”定义为简单的执行时间(或调度)和一些小的作业标识符。其他的很像Quartz的工作和触发器对象的结合。在开发Quartz时,我们认为在时间表和要在时间表上执行的工作之间创建分离是有意义的。这(在我们看来)有很多好处。
例如,可以独立于触发器在作业调度器中创建和存储作业,许多触发器可以与同一作业关联。这种松耦合的另一个好处是,可以配置在相关触发器过期后仍留在调度器中的作业,以便以后可以重新调度作业,而不必重新定义作业。它还允许您修改或替换触发器,而不必重新定义其关联的作业。
Identities
在向Quartz调度器注册作业和触发器时,会给出标识键。作业和触发器的键(JobKey和TriggerKey)允许将它们放在“组”中,这对于组织作业非常有用,并且将作业和触发器分为“报告作业”和“维护作业”等类别。作业或触发器的键的名称部分必须在组中是唯一的—换句话说,作业或触发器的完整键(或标识符)是名称和组的组合。
现在你对工作和触发点有了大致的了解,你可以在第三课:更多关于工作和触发点的内容和第四课:更多关于触发点的内容中了解它们。