Quartz (1) 入门例子

Trigger

Trigger是什么?

Quartz中的触发器用来告诉调度程序作业什么时候触发,即Trigger对象是用来触发执行job的。Quartz有两大触发器:SimpleTriggerCronTrigger
在这里插入图片描述

SimpleTrigger

SimpleTrigger可以满足的调度需求是:在具体的时间点执行一次,或者在具体的时间点执行,并且以指定的间隔重复执行若干次。

SimpleTrigger的属性包括:开始时间、结束时间、重复次数以及重复的间隔。

  • 重复次数:可以是0正整数,以及常量SimpleTrigger.REPEAT_INDEFINITELY
    REPEAT_INDEFINITELY是-1,也就是-1表示无限次。
  • 重复的间隔:必须是0,或者long型的正数,表示毫秒
    注意,如果重复间隔为0,trigger将会以重复次数并发执行(或者以scheduler可以处理的近似并发数)。
  • endTime:属性的值会覆盖设置重复次数的属性值;
    比如,你可以创建一个trigger,在终止时间之前每隔10秒执行一次,你不需要去计算在开始时间和终止时间之间的重复次数,只需要设置终止时间并将重复次数设置为REPEAT_INDEFINITELY(当然,你也可以将重复次数设置为一个很大的值,并保证该值比trigger在终止时间之前实际触发的次数要大即可)。

1.指定时间开始触发,不重复:

 SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger() 
        .withIdentity("trigger1", "group1")
        .startAt(myStartTime)                     // some Date 
        .forJob("job1", "group1")                 // identify job with name, group strings
        .build();

2.指定时间触发,每隔10秒执行一次,重复10次:

SimpleTrigger  trigger = (SimpleTrigger) TriggerBuilder.newTrigger()
        .withIdentity("trigger3", "group1")
        .startAt(myTimeToStartFiring)  // if a start time is not given (if this line were omitted), "now" is implied
        .withSchedule(simpleSchedule()
            .withIntervalInSeconds(10)
            .withRepeatCount(10)) // note that 10 repeats will give a total of 11 firings
        .forJob(myJob) // identify job with handle to its JobDetail itself                   
        .build();

3.立即触发,每隔5分钟执行一次,直到22:00:

 trigger = newTrigger()
        .withIdentity("trigger7", "group1")
        .withSchedule(simpleSchedule()
            .withIntervalInMinutes(5)
            .repeatForever())
        .endAt(dateOf(22, 0, 0))
        .build();

请查阅TriggerBuilder和SimpleScheduleBuilder提供的方法,以便对上述示例中未提到的选项有所了解。

TriggerBuilder(以及Quartz的其它builder)会为那些没有被显式设置的属性选择合理的默认值。比如:如果你没有调用withIdentity(..)方法,TriggerBuilder会为trigger生成一个随机的名称;如果没有调用startAt(..)方法,则默认使用当前时间,即trigger立即生效。

CronTrigger

基于日历的作业调度器,而不是像SimpleTrigger那样精确指定间隔时间,比SimpleTrigger更常用。

1.Cron表达式
用于配置CronTrigger实例

是由7个子表达式组成的字符串,描述了时间表的详细信息

格式:[秒][分][小时][日][月][周][年]

书写规则:知道确定日期的写上,不知道的用*代替  (年可以省略,只写前6个)

序号说明是否必填允许填写的值允许的通配符
10-59, - * /
20-59, - * /
3小时0-23, - * /
41-31, - * ? / L W
51-12 or JAN-DEC, - * /
61-7 or SUN-SAT, - * ? / L #
7empty 或 1970-2099, - * /

2.Cron表达式特殊字符意义对应表
一个完整的Cron-Expressions的例子是字符串“0 0 12?* WED“ - 这意味着”每个星期三下午12:00“。

单个子表达式可以包含范围和/或列表。例如,可以用“MON-FRI”,“MON,WED,FRI”或甚至“MON-WED,SAT”代替前一个(例如“WED”)示例中的星期几字段。

通配符(’ '字符)可用于说明该字段的“每个”可能的值。因此,前一个例子的“月”字段中的“”字符仅仅是“每个月”。因此,“星期几”字段中的“*”显然意味着“每周的每一天”。

所有字段都有一组可以指定的有效值。这些值应该是相当明显的 - 例如秒和分钟的数字0到59,数小时的值0到23。日期可以是1-31的任何值,但是您需要注意在给定的月份中有多少天!月份可以指定为0到11之间的值,或者使用字符串JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV和DEC。星期几可以指定为1到7(1 =星期日)之间的值,或者使用字符串SUN,MON,TUE,WED,THU,FRI和SAT。

  • * 字符:表示所有值。
    例如:在分的字段上设置 “*”,*表示每一分钟都会触发。

  • - 字符:表示区间。
    例如 在小时上设置 “10-12”,表示 10,11,12点都会触发。

  • ,字符 表示指定多个值。
    例如在周字段上设置 “MON,WED,FRI” 表示周一,周三和周五触发

  • / 字符:可用于指定值的增量。
    例如:
    在“分钟”字段中输入“0/15”,则表示“每隔15分钟,从零开始”。
    在“分钟”字段中使用“3/20”,则意味着“每隔20分钟,从三分钟开始” , 换句话说,等价于“分钟”字段设置为“3,23,43”。
    在日字段上设置’1/3'所示每月1号开始,每隔三天触发一次。

    请注意“ / 35”的细微之处并不代表“每35分钟” - 这意味着“每隔35分钟,从零开始” - 或者换句话说,与指定“0,35”相同。

  • 字符:表示不指定值。
    仅用在星期字段,不需要关心当前设置这个字段的值,表示一个月的每一天或一周的每天。
    例如:要在每月的10号触发一个操作,但不关心是周几,所以需要周位置的那个字段设置为"?" 具体设置为 0 0 0 10 * ?

  • L字符:last 允许用于星期字段,表示最后的意思。
    例如:
    1) “”字段中的“L”表示“月的最后一天” - 1月31日,非闰年2月28日。
    2) “”字段上表示星期六(西方把星期天当前每周的第一天,周六是最后一天),相当于"7“或”SAT"。
    3)如果在星期的字段中再次使用这个值,就意味着“该月最后一个xxx日”,例如“6L”或“FRIL”都意味着“该月的最后一个星期五”。
    4) 您还可以指定与该月最后一天的偏移量,例如“ L-3”,这表示日历月的倒数第三天。 使用“ L”选项时,不要指定列表或值的范围,这一点很重要,因为这样会导致混淆/意外的结果

  • W字符: workday 用于指定最近给定日期的工作日(星期一至星期五)。
    例如在日字段上设置"15W",表示离每月15号最近的那个工作日触发。如果15号正好是周六,则找最近的周五(14号)触发, 如果15号是周未,则找最近的下周一(16号)触发.如果15号正好在工作日(周一至周五),则就在该天触发。如果指定格式为 “1W”,它则表示每月1号往后最近的工作日触发。如果1号正是周六,则将在3号下周一触发。(注,“W"前只能设置具体的数字,不允许区间”-").

    'L’和 'W’可以一组合使用。如果在日字段上设置"LW",则表示在本月的最后一个工作日触发(一般指发工资 )

  • 序号(表示每月的第几个周几)。
    例如在周字段上设置"6#3"表示在每月的第三个周六.注意如果指定"#5",正好第五周没有周六,则不会触发该配置(用在母亲节和父亲节再合适不过了)

周字段的设置,若使用英文字母是不区分大小写的 MON 与mon相同.

3. '*‘与’?'的区别
二者意思相近,容易让人理解成可以任意替换,实际上二者是有区别的,存在如下的隐藏的约束关系:

1、如官方文档解释的那样,问号(?)的作用是指明该字段‘没有特定的值’;

2、星号(*)和其它值,比如数字,都是给该字段指明特定的值,只不过用星号(*)代表所有可能值;

3、cronExpression对日期和星期字段的处理规则是它们必须互斥,即只能且必须有一个字段有特定的值另一个字段必须是‘没有特定的值’

4、问号(?)就是用来对日期和星期字段做互斥的。

因此存在如下的错误场景:
1、当星期和日期都为*或数字时,报错 Support for specifying both a day-of-week AND a day-of-month parameter is not implemented.

即两个字段不能都指明的特定的值,必须互斥。这里的*和数字是一样的,如果都指明特定的数字,也是报一样的错。

2、 当星期和日期有一个为数字另一个为*时,报错:

Support for specifying both a day-of-week AND a day-of-month parameter is not implemented.

原因同一,因为*是数字的变种,本质上也是特定的数字。

3、当星期和日期都为?时,报错 :
'?' can only be specfied for Day-of-Month -OR- Day-of-Week.

以下是一些表达式及其含义的更多示例 - 您可以在JavaDoc中找到更多的org.quartz.CronExpression

Cron Expressions示例

CronTrigger示例1 - 创建一个触发器的表达式,每5分钟就会触发一次

“0 0/5 * * *?”

CronTrigger示例2 - 创建触发器的表达式,每5分钟触发一次,分钟后10秒(即上午10:00:10,上午10:05:10等)。

“10 0/5 * * *?”

CronTrigger示例3 - 在每个星期三和星期五的10:30,11:30,12:30和13:30创建触发器的表达式。

“0 30 10-13?* WED,FRI“

CronTrigger示例4 - 创建触发器的表达式,每个月5日和20日上午8点至10点之间每半小时触发一次。请注意,触发器将不会在上午10点开始,仅在8:00,8:30,9:00和9:30

“0 0/30 8-9 5,20 *?”

请注意:
1.一些调度要求太复杂,无法用单一触发表示 - 例如“每上午9:00至10:00之间每5分钟,下午1:00至晚上10点之间每20分钟”一次。在这种情况下的解决方案是简单地创建两个触发器,并注册它们来运行相同的作业。

配置Maven依赖

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.2.3</version>
</dependency>
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz-jobs</artifactId>
    <version>2.2.3</version>
</dependency> 

完整例子

HelloJob.java,共用

import java.util.Date;

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

public class HelloJob implements Job {
    public void execute(JobExecutionContext arg0) throws JobExecutionException {
        System.out.println("HelloJob...." + new Date());
    }
}

1.SimpleTrigger例子

import java.util.concurrent.TimeUnit;

import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;

public class Test {
    public static void main(String[] args) throws InterruptedException {
        Scheduler scheduler;
        try {
            scheduler = StdSchedulerFactory.getDefaultScheduler();
            System.out.println("quartz start....");
            scheduler.start();
            /********************** doWork() start **************/
            // 每五秒执行一次
            JobDetail jobDetail = JobBuilder.newJob(HelloJob.class).withIdentity("job1", "group1")
                    .build();
            SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
                    .withIntervalInSeconds(5).repeatForever();
            Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
                    .startNow().withSchedule(simpleScheduleBuilder).build();
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }

    }
}

2.CronTrigger例子

import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;

public class Test2 {
    public static void main(String[] args) throws InterruptedException {
        Scheduler scheduler;
        try {
            scheduler = StdSchedulerFactory.getDefaultScheduler();
            System.out.println("quartz start....");
            scheduler.start();
            /********************** doWork() start **************/
            // 每秒执行一次
            JobDetail jobDetail = JobBuilder.newJob(HelloJob.class).withIdentity("job1", "jobGroup1")
                    .build();
            Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
                    .startNow().withSchedule(CronScheduleBuilder.cronSchedule("* * * * * ? *"))
                    .build();
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }

    }

总结

无论哪种trigger,最终都要调用

scheduler.scheduleJob(jobDetail, trigger);

因此如果想搜索工程中用到的所有定时任务,可以搜索scheduleJob

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值