Quartz(1-Job)
|总字数:2.9k|阅读时长:12分钟|浏览量:|
基本使用
1 2 3 4 5
| <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.3.1</version> </dependency>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| public class HelloJob implements Job {
@Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { Date fireTime = jobExecutionContext.getFireTime(); System.out.println("fireTime:" + fireTime); Date previousFireTime = jobExecutionContext.getPreviousFireTime(); System.out.println("previousFireTime:" + previousFireTime); Date nextFireTime = jobExecutionContext.getNextFireTime(); System.out.println("nextFireTime:" + nextFireTime); Date scheduledFireTime = jobExecutionContext.getScheduledFireTime(); System.out.println("scheduledFireTime:" + scheduledFireTime);
JobDetail jobDetail = jobExecutionContext.getJobDetail(); System.out.println("jobDataMap:" + JSON.toJSONString(jobDetail.getJobDataMap())); System.out.println("jobKey:" + JSON.toJSONString(jobDetail.getKey())); System.out.println("jobDescription:" + jobDetail.getDescription()); System.out.println("=================================="); }
public static void main(String[] args) throws SchedulerException { JobDetail jobDetail = JobBuilder .newJob(HelloJob.class) .withIdentity("hello","group1") .withDescription("Quartz测试") .usingJobData("name", "小米") .usingJobData("age", 15) .build();
SimpleTrigger trigger = TriggerBuilder.newTrigger() .withIdentity("myTrigger", "group1") .startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(2) .repeatForever()) .build(); StdSchedulerFactory factory = new StdSchedulerFactory(); Scheduler scheduler = factory.getScheduler(); scheduler.start(); scheduler.scheduleJob(jobDetail, trigger); } }
|
JobExecutionContext
当 Scheduler 调用一个 Job 就会将 JobExecutionContext 传递给 Job 的 execute()方法,Job 能通过 JobExecutionContext 对象访问到 Quartz 运行时候的环境和 Job 本身的明细数据
JobDetail、JobBuilder
方法
- storeDurably
JobDetails 信息持久化到数据库的时候有一个属性 storeDurably,如果设置为 true 则无论与其关联的 Trigger 是否存在其都会一直存在,否则只要相关联的 trigger 删除掉了其会自动删除掉
- requestRecovery
请求恢复,也就是说当应用发生故障的时候,是否重新执行默认是 false。如果一个 job 是可恢复的,并且在其执行的时候,scheduler 发生硬关闭(hard shutdown)(比如运行的进程崩溃了,或者关机了),则当 scheduler 重新启动的时候,该 job 会被重新执行。此时,该 job 的 JobExecutionContext.isRecovering() 返回 true
- usingJobData、setJobData
添加 Job 数据,每个 JobDetail 内都有一个 JobDataMap,包含了关联到这个 Job 的数据,在 Job 类中,可以通过 context 取出该数据,进行业务流程处理。
- withIdentity
给 JobDetail 起一个 Id,方便后面检索
- withDescription
用来对 job 进行描述,并没有什么实际作用
JobKey
JobKey 是表明 Job 身份的一个对象,里面封装了 Job 的 name 和 group,TriggerKey 同理。当不指定 group 时,Quartz 会用默认的组名 DEFAULT
JobDataMap
JobDetail 是任务的定义,而 Job 是任务的执行逻辑,每一个 JobDetail 都会有一个 JobDataMap,JobDataMap 本质就是一个 Map 的扩展类,可以存储一些任务信息
JobDataMap 获取任务信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| public class HelloJob implements Job {
@Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { JobDetail jobDetail = jobExecutionContext.getJobDetail(); JobDataMap jobDataMap = jobDetail.getJobDataMap(); System.out.println("name:" + jobDataMap.getString("name")); System.out.println("age:" + jobDataMap.getInt("age")); System.out.println("jobKey:" + JSON.toJSONString(jobDetail.getKey())); System.out.println("jobDescription:" + jobDetail.getDescription()); System.out.println("=================================="); }
public static void main(String[] args) throws SchedulerException { JobDetail jobDetail = JobBuilder .newJob(HelloJob.class) .withIdentity("hello","group1") .withDescription("Quartz测试") .usingJobData("name", "小米") .usingJobData("age", 15) .build();
SimpleTrigger trigger = TriggerBuilder.newTrigger() .withIdentity("myTrigger", "group1") .startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(2) .repeatForever()) .build(); StdSchedulerFactory factory = new StdSchedulerFactory(); Scheduler scheduler = factory.getScheduler(); scheduler.start(); scheduler.scheduleJob(jobDetail, trigger); } }
|
实体类获取任务信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| public class HelloJob3 implements Job {
private String message; private Float floatJobValue; private Double doubleTriggerValue;
public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; }
public Float getFloatJobValue() { return floatJobValue; }
public void setFloatJobValue(Float floatJobValue) { this.floatJobValue = floatJobValue; }
public Double getDoubleTriggerValue() { return doubleTriggerValue; }
public void setDoubleTriggerValue(Double doubleTriggerValue) { this.doubleTriggerValue = doubleTriggerValue; }
@Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { Date date = new Date(); SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("现在的时间是:" + sf.format(date)); System.out.println("jobDataMap定义的message的值 : " + message); System.out.println("jobDataMap定义的floatJobValue的值 : " + floatJobValue); System.out.println("=================================="); }
public static void main(String[] args) throws SchedulerException { JobDetail jobDetail = JobBuilder .newJob(HelloJob3.class) .withIdentity("myJob", "group1") .usingJobData("message","hello myJob1") .usingJobData("FloatJobValue",8.88f) .build();
SimpleTrigger trigger = TriggerBuilder.newTrigger() .withIdentity("myTrigger", "group1") .startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(2) .repeatForever()) .build(); StdSchedulerFactory factory = new StdSchedulerFactory(); Scheduler scheduler = factory.getScheduler(); scheduler.start(); scheduler.scheduleJob(jobDetail,trigger); } }
|
注解使用
@PersistJobDataAfterExecution
有状态的 Job 可以理解为多次 Job 调用期间可以持有一些状态信息,这些状态信息存储在 JobDataMap 中,而默认的无状态 Job 每次调用时都会创建一个新的 JobDataMap
注意:没有添加@PersistJobDataAfterExecution 注解,每次调用时都会创建一个新的 JobDataMap,不会累加;添加该注解后,多次调用期间可以持有一些状态信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| @PersistJobDataAfterExecution public class HelloJob4 implements Job {
private Integer count;
public void setCount(Integer count) { this.count = count; }
@Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { System.out.println(++count); jobExecutionContext.getJobDetail().getJobDataMap().put("count", count); }
public static void main(String[] args) throws SchedulerException { JobDetail jobDetail = JobBuilder .newJob(HelloJob4.class) .withIdentity("myJob", "group1") .usingJobData("count",0) .build();
SimpleTrigger trigger = TriggerBuilder.newTrigger() .withIdentity("myTrigger", "group1") .startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(2) .repeatForever()) .build(); StdSchedulerFactory factory = new StdSchedulerFactory(); Scheduler scheduler = factory.getScheduler(); scheduler.start(); scheduler.scheduleJob(jobDetail,trigger); } }
|
@DisallowConcurrentExecution
禁止并发执行多个相同定义的 JobDetail,这个注解是加在 Job 类上的,但意思并不是不能同时执行多个 Job,而是不能并发执行同一个 Job
例如:同一个 Job 实现类 DemoJob 的两个 JobDetail 实例 A 和 B,设置 A 的定时执行频率为每 1 分钟执行一次,A 的实际运行耗时为 3 分钟,B 的定时执行频率也是每 1 分钟执行一次,B 的实际运行耗时为 30 秒。假如在 07:00 分 00 秒时 A 和 B 同时第一次运行,则到 07:00 分 30 秒时 B 运行结束,此时 A 还在运行中,到 07:01 分 00 秒时 A 和 B 又该执行了,但是由于注解@DisallowConcurrentExecution 的缘故,此时 A 不会再次运行,A 只能在其上一次运行结束后才能再次被调用执行。但是 B 会正常运行(B 不受 A 的影响,注解@DisallowConcurrentExecution 是作用于 JobDetail 实例而不是 Job 实现类)
注意:如果你使用了@PersistJobDataAfterExecution 注解,则强烈建议你同时使用@DisallowConcurrentExecution 注解,因为当同一个 job(JobDetail)的两个实例被并发执行时,由于竞争,JobDataMap 中存储的数据很可能是不确定的。
使用同一个Job对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| @DisallowConcurrentExecution public class HelloJob5 implements Job {
@Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { Date date = new Date(); SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("现在的时间是:" + sf.format(date)); JobKey key = jobExecutionContext.getJobDetail().getKey(); System.out.println("jobDetail 的name : " + key.getName()); System.out.println("jobDetail 的group : " + key.getGroup()); System.out.println("=============================="); try { Thread.sleep(3000); } catch (InterruptedException e) { throw new RuntimeException(e); } }
public static void main(String[] args) throws SchedulerException { JobDetail jobDetail1 = JobBuilder .newJob(HelloJob5.class) .withIdentity("group1", "group1") .build();
SimpleTrigger trigger1 = TriggerBuilder.newTrigger() .withIdentity("myTrigger1", "group1") .startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(2) .repeatForever()) .build(); StdSchedulerFactory factory = new StdSchedulerFactory(); Scheduler scheduler = factory.getScheduler(); scheduler.start(); scheduler.scheduleJob(jobDetail1, trigger1); } }
|
- 使用@DisallowConcurrentExecution前
1 2 3 4 5 6 7 8 9 10 11 12 13
| 现在的时间是:2024-11-12 00:59:49 jobDetail 的name : group1 jobDetail 的group : group1 ============================== 现在的时间是:2024-11-12 00:59:52 jobDetail 的name : group1 jobDetail 的group : group1 ============================== 现在的时间是:2024-11-12 00:59:55 jobDetail 的name : group1 jobDetail 的group : group1 ==============================
|
- 使用@DisallowConcurrentExecution后
1 2 3 4 5 6 7 8 9 10 11 12 13
| 现在的时间是:2024-11-12 01:00:48 jobDetail 的name : group1 jobDetail 的group : group1 ============================== 现在的时间是:2024-11-12 01:00:50 jobDetail 的name : group1 jobDetail 的group : group1 ============================== 现在的时间是:2024-11-12 01:00:52 jobDetail 的name : group1 jobDetail 的group : group1 ==============================
|
创建两个 Job 对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| @DisallowConcurrentExecution public class HelloJob5 implements Job {
@Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { Date date = new Date(); SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("现在的时间是:" + sf.format(date)); JobKey key = jobExecutionContext.getJobDetail().getKey(); System.out.println("jobDetail 的name : " + key.getName()); System.out.println("jobDetail 的group : " + key.getGroup()); System.out.println("=============================="); try { Thread.sleep(3000); } catch (InterruptedException e) { throw new RuntimeException(e); } }
public static void main(String[] args) throws SchedulerException { JobDetail jobDetail1 = JobBuilder .newJob(HelloJob5.class) .withIdentity("group1", "group1") .build();
SimpleTrigger trigger1 = TriggerBuilder.newTrigger() .withIdentity("myTrigger1", "group1") .startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(2) .repeatForever()) .build(); StdSchedulerFactory factory = new StdSchedulerFactory(); Scheduler scheduler = factory.getScheduler(); scheduler.start(); scheduler.scheduleJob(jobDetail1, trigger1);
JobDetail jobDetail2 = JobBuilder .newJob(HelloJob5.class) .withIdentity("group2", "group2") .build();
SimpleTrigger trigger2 = TriggerBuilder.newTrigger() .withIdentity("myTrigger2", "group2") .startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(3) .repeatForever()) .build(); Scheduler scheduler2 = factory.getScheduler(); scheduler2.start(); scheduler2.scheduleJob(jobDetail2, trigger2); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 现在的时间是:2024-11-12 01:08:37 现在的时间是:2024-11-12 01:08:37 jobDetail 的name : group2 jobDetail 的name : group1 jobDetail 的group : group1 jobDetail 的group : group2 ============================== ============================== 现在的时间是:2024-11-12 01:08:40 jobDetail 的name : group2 jobDetail 的group : group2 ============================== 现在的时间是:2024-11-12 01:08:40 jobDetail 的name : group1 jobDetail 的group : group1 ==============================
|