Quartz任务调度快速入门进阶三——Trigger触发器

689 阅读8分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

Trigger介绍

graph TD
A[TriggerBuilder] -->|创建| B(Trigger)
C[AbstractTrigger] --> B
C1[DailyTimeIntervalTriggerImpl] --> C
C2[CalendarIntervalTriggerImpl] --> C
C3[SimpleTriggerImpl] --> C
C4[CronTriggerImpl] --> C

Quartz有一些不同的触发类型,常用的时SimpleTrigger和CronTrigger。

  1. JobKey 表示Job实例的标识,触发器被出发时,该指定的Job实例会被执行。

  2. startTime 表示触发器的时间表,第一次开始被触发的时间,它的数据类型时java.util.Date,要配合startAt()方法使用。

  3. endTime 指定触发器终止被触发的时间,它的数据类型是java.util.Date,要配合endAt()方法使用。

案例: HelloJobTrigger.java

// 定义任务类
public class HelloJobTrigger implements Job{
    
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException{
        // 定义时间
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = dateFormat.format(date);
        
        // 定义工作任务内容
        System.out.println("进行数据库备份操作,当前任务执行的时间:"+dateString);
        
        // 获取jobKey,startTime,endTime
        Trigger trigger = context.getTrigger();
        System.out.println("jobKey的标识:"+trigger.getJobKey().getName()+",jobkey的组名"+trigger.getJobKey().getGroup());
        System.out.println("任务的开始时间:"+trigger.getStartTime+",任务的结束时间"+trigger.getEndTime());
    }
}

HelloSchedulerDemoTrigger.java

public class HelloSchedulerDemoTrigger{
    public static void main(Stringp[] args) throws Exception{ 
        //1:从工厂中获取任务调度的实例 
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); 
        
        // 定义日期
        Date startDate = new Date();
        // 启动任务,任务在当前时间3秒后执行
        startDate.setTime(startDate.getTime()+3000);
        // 定义日期
        Date endDate = new Date();
        // 启动任务,任务在当前时间10秒后停止
        endDate.setTime(endDate.getTime()+10000);
        
        
        //2:定义一个任务调度实例,将该实例与HelloJob绑定,任务类需要实现Job接口 
        JobDetail job = JobBuilder.newJob(HelloJobTrigger.class) 
                .withIdentity("job1", "group1") //定义该实例唯一标识 
                .build(); 
        
        //3:定义触发器,马上执行,然后每5秒重复执行一次 
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1") // 定义该实例唯一标识 
                .startAt(startDate)
                .endAt(endDate)
                .withScheduler(SimpleSchedulerBuilder.simpleScheduler() .repeatSecondlyForever(5)) // 每5秒执行一次
                .build(); 
        
        //4:使用触发器调度任务的执行 
        scheduler.schedulerJob(job, trigger); 
        
        //5:开启 
        scheduler.start();
        
        //6:关闭 
        scheduler.shutdown();   
     }
}

SimpleTrigger触发器

SimpleTrigger对于设定和使用是最为简单的一种QuartzTrigger。

它是为那种在特定的日期/时间启动,且以一个可能的间隔时间重复执行n次的Job所设计的。

案例一:表示在一个指定的时间段内,执行一次作业任务;

HelloJobSimpleTrigger.java

// 定义任务类
public class HelloJobSimpleTrigger implements Job{
    
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException{
        // 定义时间
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = dateFormat.format(date);
        
        // 定义工作任务内容
        System.out.println("进行数据库备份操作,当前任务执行的时间:"+dateString);
        
    }
}

HelloSchedulerDemoSimpleTrigger.java

public class HelloSchedulerDemoSimpleTrigger{
    public static void main(Stringp[] args) throws Exception{ 
        //1:从工厂中获取任务调度的实例 
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); 
        
        // 设置任务的开始时间
        Date startDate = new Date();
        // 启动任务,任务在当前时间3秒后执行
        startDate.setTime(startDate.getTime()+3000);
        
        
        //2:定义一个任务调度实例,将该实例与HelloJob绑定,任务类需要实现Job接口 
        JobDetail job = JobBuilder.newJob(HelloJobSimpleTrigger.class) 
                .withIdentity("job1", "group1") //定义该实例唯一标识 
                .build(); 
        
        //3:定义触发器,马上执行,然后每5秒重复执行一次 
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1") // 定义该实例唯一标识 
                .startAt(startDate)
                .build(); 
        
        //4:使用触发器调度任务的执行 
        scheduler.schedulerJob(job, trigger); 
        
        //5:开启 
        scheduler.start();
        
        //6:关闭 
        scheduler.shutdown();   
     }
}

案例二:或在指定的时间间隔内多次执行作业任务

修改HelloSchedulerDemoSimpleTrigger.java

// 3:定义触发器,马上执行,然后每5秒重复执行一次
Trigger trigger = TriggerBuilder.newTrigger()
            .withIdentity("trigger1", "group1") // 定义该实例唯一标识
            .startAt(startDate)
            .withSchedule(SimpleScheduleBuilder.simpleSchedule().repeateSecondlyForever(5)
                    .withRepeatCount(3)) // withRepeatCount()方法设定执行次数,参数是int类型,默认值是0
            .build();

案例三:指定任务的结束时间(结束时间优先级高于重复次数

修改HelloSchedulerDemoSimpleTrigger.java

// 定义日期
Date endDate = new Date();
// 启动任务,任务在当前时间10秒后停止     
endDate.setTime(endDate.getTime()+10000);

//2:定义一个任务调度实例,将该实例与HelloJob绑定,任务类需要实现Job接口 
JobDetail job = JobBuilder.newJob(HelloJobSimpleTrigger.class) 
            .withIdentity("job1", "group1") //定义该实例唯一标识 
            .build(); 
            
 //3:定义触发器,马上执行,然后每5秒重复执行一次 
Trigger trigger = TriggerBuilder.newTrigger()
          .withIdentity("trigger1", "group1") // 定义该实例唯一标识 
          .startAt(startDate)
          .endAt(endDate)
          .withScheduler(SimpleScheduleBuilder.simpleSchedule().repeateSecondlyForever(5)
                    .withRepeatCount(3)) // 每5秒执行一次
          .build();

注意:

  • SimpleTrigger的属性有:开始时间、结束时间、重复次数、重复的时间间隔
  • 重复次数属性的值可以为0,正整数、常量 SimpleTrigger.REPEAT_INDEFINITELT(值为-1,反复执行;相当于不设该属性
  • 重复的时间间隔属性值必须为大于0或长整形的正整数,以毫秒作为时间的那位,当重复的时间间隔为0时,意味着与Trigger同时触发执行
  • 如果有指定结束时间属性值,则结束时间属性优先于重复次数属性,这样的好处在于:当我们需要创建一个每间隔10秒钟触发一次直到指定的结束时间的Trigger,而无需取计算从开始到结束的所重复的次数,我们只需简单的指定结束时间和使用REPEAT_INDEFINITELY作为重复次数的属性值即可。

CronTrigger触发器

如果需要像日历那样按日程来触发任务,而不是像SimpleTrigger那样每隔特定的间隔时间触发,CronTrigger通常比SimpleTrigger更有用,因为他是基于日历的作业调度器。

使用CronTrigger,你可以指定诸如“每个周五中午”,或者“每个工作日的9:30”或者“从每个周一、周三、周五的上午9:00到10:00之间每间隔五分钟”这样日程安排来触发。甚至,像SimpleTrigger一样,CronTrigger也有一个startTime以指定日期从什么时候开始,也有一个(可选的)endTime以指定何时日程不再继续。

CronExpression —— Cron表达式

Cron表达式被用来配置CronTrigger实例。Cron表达式是一个由7个子表达式组成的字符串。每个子表达式都描述了一个单独的日程细节。这些子表达式用空格分隔,分别表示:

  1. Seconds 秒
  2. Minutes 分钟
  3. Hours 小时
  4. Day-of-Month 月中的天
  5. Month 月
  6. Day-of-Week 周中的天
  7. Year(optional field)年(可选的域)

取值:

字段是否必填允许值运行的特殊字符
0-59, - * /
0-59, - * /
小时0-23, - * /
1-31, - * / ? L W C
1-12 或 JAN-DEC, - * /
1-7 或 SUN-SAT(1=星期天, - * / ? L C #
不填写 或 1970-2009, - * /
特殊符号含义
*用来表示域中“每个”可能的值。因此在“Month”域中的 * 表示每个月,而在 Day-of-Week 域中表示的 * 则表示“周中的每一天”
?表示不指定值,使用的场景为不需要关系当前设置这个字段的值。因此“月份中的日期”和“星期中的日期”这两个元素是互斥的,因此应该通过设置一个问号 (?) 来表明不设置的那个字段
-表示区间,例如在小时商设置10-12,表示10、11、12点都会触发
,表示指定多个值,例如在周字段上设置“MON, WED, FRI”,表示周一、周三、周五触发
/表示值的增量,例如如果分钟域中放入“0/15”,它表示“每隔15分钟,从0开始”,如果在分钟域中使用“3/20”,则表示“小时中每隔20分钟,从3分钟开始”或者另外相同的形式就是“3,23,43”
L可以在day-of-month、day-of-week中使用,这个字符是“last”的简写,但是在两个域中的意义不同。例如:在day-of-month域中“L”表示这个月的最后一天;造day-of-week中,表示“7”或“SAT”。但是如果在day-of-week域中,这个字符跟在别的值后面,则表示“当月的最后的周XXX”,例如:“6L”或者“FRIL”都表示本月的最后一个周五。当使用“L”选项时,最重要的时不要指定列表或者值范围,否则会导致混乱
W用来指定距离给定日最接近的周几(在day-of-week域中指定),例如:如果为day-of-month域指定为“15w”,则表示“距离月中15号最近的周几”
#表示月中国的第几个周几,例如:day-of-week 域中的“6#3”或者“FRI#3”表示“月中第三个周五”

案例: HelloJobCronTrigger.java

// 定义任务类
public class HelloJobCronTrigger implements Job{
    
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException{
        // 定义时间
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = dateFormat.format(date);
        
        // 定义工作任务内容
        System.out.println("进行数据库备份操作,当前任务执行的时间:"+dateString);
        
    }
}

HelloSchedulerDemoCronTrigger.java

public class HelloSchedulerDemoCronTrigger{
    public static void main(Stringp[] args) throws Exception{ 
        //1:从工厂中获取任务调度的实例 
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); 
        
        // 设置任务的开始时间
        Date startDate = new Date();
        // 启动任务,任务在当前时间3秒后执行
        startDate.setTime(startDate.getTime()+3000);
         // 设置任务的开始时间
        Date endDate = new Date();
        // 启动任务,任务在当前时间10秒后结束
        endDate.setTime(endDate.getTime()+10000);
        
        //2:定义一个任务调度实例,将该实例与HelloJob绑定,任务类需要实现Job接口 
        JobDetail job = JobBuilder.newJob(HelloJobSimpleTrigger.class) 
                .withIdentity("job1", "group1") //定义该实例唯一标识 
                .build(); 
        
        //3:定义触发器,马上执行,然后每5秒重复执行一次 
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1") // 定义该实例唯一标识 
                //.startAt(startDate)
                //.endAt(endDate)
                .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")) // 日历 每隔5秒执行一次
                .build(); 
        
        //4:使用触发器调度任务的执行 
        scheduler.schedulerJob(job, trigger); 
        
        //5:开启 
        scheduler.start();
        
        //6:关闭 
        scheduler.shutdown();   
     }
}

提示:

  • L和W可以一起用。(企业可用在工资计算)
  • #可表示月中第几个周几。(企业可用在计算母亲节、父亲节)
  • 周字段英文字母不区分大小写,例如MON==mon
  • 利用工具,在线生成