Quartz教程 - 5触发器

本文介绍了Quartz框架中的CronTrigger及其在定义复杂任务调度方面的应用,包括Cron表达式的解读,以及Misfire策略在处理任务错过执行时的不同处理方式。
摘要由CSDN通过智能技术生成

更好的阅读体验:点这里www.doubibiji.com

5 触发器

触发器(Triggers)用于定义何时和如何执行与 Job 关联的任务。它们决定了任务的调度规则,比如何时执行、执行频率以及在何种条件下触发执行。

我们在前面使用的触发器是SimpleTrigger, SimpleTrigger 只能定义按照指定频率执行的任务,如果要定义复杂的执行规则,SimpleTrigger 是无法支持的,一般我们用的最多的就是 CronTrigger

5.1 CronTrigger

CronTrigger 是 Quartz 中用于基于 Cron 表达式定义任务执行时间表的触发器类型。它允许用户按照日历时间来定义任务的执行规则,非常灵活且支持各种复杂的调度需求。

1 CronTrigger演示

先举个栗子:

任务还是之前的任务类:

MyJob.java

package com.doubibiji.job;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.text.SimpleDateFormat;
import java.util.Date;

public class MyJob implements Job {

    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("执行任务:" + sdf.format(new Date()));
    }
}

编写测试类,代码如下:

package com.doubibiji;
import com.doubibiji.job.MyJob;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.util.concurrent.TimeUnit;

public class TestClass {

    public static void main(String[] args) {

        // 1.定义jobDetail
        JobDetail job = JobBuilder.newJob(MyJob.class)
                .withIdentity("job1", "jGroup1")
                .usingJobData("count", 0)           // 通过key-value形式设置参数
                .build();

        // 2.创建一个 Cron 触发器
        CronTrigger cronTrigger = TriggerBuilder.newTrigger()
                .withIdentity("cronTrigger1", "cGroup1")
                .startAt(DateBuilder.futureDate(10, DateBuilder.IntervalUnit.SECOND)) // 延迟10秒执行
                .withSchedule(CronScheduleBuilder.cronSchedule("*/2 * * * * ?"))
                .build();

        try {
            // 3.定义调度器
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            // 设置任务和触发器,由触发器进行分派任务
            scheduler.scheduleJob(job, cronTrigger);
            scheduler.start();

            // 让主线程延迟执行,scheduler如果shutdown,则所有的定时任务会取消。
            TimeUnit.SECONDS.sleep(20);
            scheduler.shutdown();
        } catch (SchedulerException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

上面的代码和之前的 HelloWorld 基本是一样的,只是使用了不同的触发器。

上面定义了 CronTrigger 触发器,使用 Cron 表达式 */2 * * * * ? 来定义执行规则,并时候用 startAt 推迟了10秒执行。

这个 Cron 表达式看上去有点懵逼,如果不会写表达式,可以百度一下 Cron 表达式在线工具,有很多网站可以编写 Cron 表达式

下面简单介绍一下 Cron 表达式

2 Cron 表达式基础

Cron 表达式由 7 个字段组成,用空格分隔:

秒 分 时 日 月 周 年(可选)
  • 秒(Seconds): 0-59 或者使用特殊字符(*-,/)表示范围和间隔。
  • 分(Minutes): 0-59 或者使用特殊字符(*-,/)表示范围和间隔。
  • 小时(Hours): 0-23 或者使用特殊字符(*-,/)表示范围和间隔。
  • 日期(Day of month): 1-31 或者使用特殊字符(*-,/?LW)表示范围和间隔。
  • 月份(Month): 1-12 或者使用特殊字符(*-,/)表示范围和间隔。
  • 星期(Day of week): 1-7(1 表示周日)或者使用特殊字符(*-,/?L#)表示范围和间隔。
  • 年(Year): 可选字段,可以指定特定的年份,通常不填。

特殊字符的含义:

特殊字符的含义:

  • 星号 (\*): 代表“所有值”。当在一个字段中使用星号时,表示该字段的所有可能值。例如,*在分钟字段中表示每分钟都执行。

  • 连字符 (-): 用于定义范围。指定一个范围的数值,例如在小时字段中,9-17 表示从9点到17点的时间范围。

  • 逗号 (,): 用于列举多个值。在一个字段中可以指定多个数值,例如在星期字段中,MON,WED,FRI 表示星期一、星期三和星期五。

  • 斜线 (/): 用于定义间隔。指定一个范围内的间隔值,例如在分钟字段中,*/15 表示每隔15分钟执行一次。

  • 问号 (?): 在日和星期字段中,问号用于指定未指定值。通常在某一个字段中指定值,但对另一个字段不关心时使用。例如,* * ? * MON-FRI 表示在工作日每分钟都执行。

  • L(L): 在日期和星期字段中,表示“最后”。例如,在日期字段中,L 表示月份的最后一天;在星期字段中,L 表示周六。

  • W(W): 在日期字段中,表示工作日(周一至周五)最接近指定的日期。例如,15W 表示最接近每月15号的工作日。

  • 井号(#): 在星期字段中,用于确定月份的第几个周几。例如,6#3 表示每月的第三个周五。

3 Cron 表达式示例

  • 每天下午 1 点执行任务:

    0 0 13 * * ?
    
  • 每隔5分钟执行一次:

    0 */5 * * * ?
    
  • 周一到周五上午 9 点到下午 5 点,每隔半小时执行一次:

    0 */30 9-17 * * MON-FRI
    
  • 在每月的最后一天,上午10点执行任务:

    0 0 10 L * ?
    

5.2 MisFire策略

在 Quartz 中,Misfire指的是触发器错过了预定的触发时间。

例如下面一些情况可能会导致任务错过执行:

  • 当前没有空闲的线程池资源可用调度器暂停;
  • 系统宕机;
  • 使用了 @DisallowConcurrentExecution 注解,要执行下一次任务了,但是上一次任务还没有执行完成;
  • 指定了过期开始的执行时间,现在是08:00:00,指定开始执行时间为06:00:00;

对于 CronTrigger 是否构成 misfire,有两个条件:

  • job 到达触发时间时没有被执行;
  • job 延迟执行的时间超过了Quartz 配置的 misfireThreshold 阈值。如果延迟执行的时间小于阈值,则 Quartz 不认为发生了misfire,会立即执行 job;如果延迟执行的时间大于或者等于阈值,则被判断为misfire,然后会按照指定的策略来执行。如果没有配置 Quartz 的 misfireThreshold,默认配置为60秒。

Quartz 针对 CronTrigger 错过触发提供了不同的 Misfire 策略,确保作业能够尽可能地被执行。

Misfire策略由 withMisfireHandlingInstructionXXX()方法来设置,其中 XXX 可以是IgnoreMisfires()DoNothing()FireAndProceed(),下面讲解一下。

1 withMisfireHandlingInstructionDoNothing()

作用:所有错过的触发都被忽略,并按照原计划执行任务,也就是错过的就错过了,等待下一次执行时间到了再执行。

举个栗子:

Trigger trigger = TriggerBuilder.newTrigger()
    .withIdentity("trigger1", "group1")
    .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")
    .withMisfireHandlingInstructionDoNothing())
    .build();

2 withMisfireHandlingInstructionFireAndProceed()

作用:错过了很多次,但是只会立即执行一次,然后按照原计划执行任务。这个是默认的策略!

举个栗子:

Trigger trigger = TriggerBuilder.newTrigger()
    .withIdentity("trigger1", "group1")
    .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")
    .withMisfireHandlingInstructionFireAndProceed())
    .build();

3 withMisfireHandlingInstructionIgnoreMisfires()

作用:立即执行所有错过的触发,错过了100个,一下子把错过的100个全部执行了,然后按照原计划执行任务。

举个栗子:

Trigger trigger = TriggerBuilder.newTrigger()
    .withIdentity("trigger1", "group1")
    .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")
    .withMisfireHandlingInstructionIgnoreMisfires())
    .build();

在实际使用中,根据您的需求选择合适的Misfire策略非常重要,这可以确保即使在意外情况下,任务也能够按照期望的方式执行。

因为现在还没有将 Quartz 的数据持久化到数据库,所以现在使用策略会发现没有效果,继续向后学习,在后面讲到将 Quartz 的数据持久化到数据库后,然后停掉项目,重新启动后,Quart 会重新启动运行,并使用不同的策略恢复任务,就可以看到效果了,例如配置为withMisfireHandlingInstructionIgnoreMisfires(),你会发现项目重新启动后,可能会出现立刻执行了很多次任务,因为这些任务是停掉项目后错过的。

  • 28
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山石岐渡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值