springboot 整合quartz (二):jobDataMap和trigger

jobDataMap

jobDataMap可以用来装载可序列化的对象,用于在job执行的时候获取。

注:jobDetailtrigger中都可以添加jobDataMap,后面的对象会把前面对象相同键值对象的值覆盖

job实体类创建代码(创建job示例,添加jobDataMap)

 public static void main(String[] args) throws SchedulerException, ParseException {
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        scheduler.start();

        // 定义job,绑定我们的定时任务
        JobDetail job2 = newJob(HelloJob.class)
                .usingJobData("name", "李四")
                .usingJobData("characteristic", "22")
                .build();

        // 执行任务,用定义好的触发器 和 任务
        scheduler.scheduleJob(job2, getTrigger1());

    }

job类代码(job运行示例,获取jobDataMap)

       public void execute(JobExecutionContext context) throws JobExecutionException {
        JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();

        String name = jobDataMap.get("name").toString();
        String characteristic = jobDataMap.get("characteristic").toString();

        JobDataMap mergedJobDataMap = context.getMergedJobDataMap();
        String mergedName = mergedJobDataMap.getString("name");

        System.out.println("name : " + name);
        System.out.println("mergedName:" + mergedName);

        System.out.println("characteristic : " + characteristic);

    }

trigger

 /**
     * 触发器立即触发,然后每隔2秒 触发一次,22:55:00:
     */
    private static SimpleTrigger getTrigger1() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

        //定义一个任务触发器
        return TriggerBuilder.newTrigger()
                .withIdentity("job2", "group2")
                //定点触发
                //.startAt(sdf.parse("2018-09-27 10:27:00"))
                // 五秒钟后触发
                .startAt(DateBuilder.futureDate(5, DateBuilder.IntervalUnit.SECOND))
                .withSchedule(
                        simpleSchedule()
                        .withIntervalInSeconds(2)
                        .repeatForever()
                        //.withRepeatCount(0)
                )
                .usingJobData("name",",,")
                //.endAt(DateBuilder.dateOf(22, 55, 0))
                .build();
    }

测试结果:

name : 李四
mergedName:,,
characteristic : 22

trigger

trigger是触发器,任务何时运行、运行几次,它说了算。

TriggerKey

  • TriggerKey:triggerKey是所有触发器的标识信息。
  • JobKey: job示例的表示信息,触发器被触发时,该指定的job示例会运行

TriggerKey介绍

设置TriggerKey可以通过JobBuilder的.withIdentity() 进行设置,如下:默认api提供三种方式 <img src="https://ws3.sinaimg.cn/mw690/005AQjvJly1fw41dc8fvjj30s608wq4z.jpg" alt="image">

全参数的源码如下:

public TriggerBuilder<T> withIdentity(String name, String group) {
        key = new TriggerKey(name, group);
        return this;
}

注:name属性是必填的,group不写,默认值为:default

JobKey大同小异,不予介绍。

其他通用属性

  • startTime:启动时间,默认当前时间,立即执行
  • endTime:自行设置,默认为空
  • priority: 优先级,默认为5,用于多个Trigger并发执行。

simpleTrigger

使用场景:在一个指定时间段内执行一次作业任务或是在指定的时间间隔内多次执行作业任务,SimpleTrigger应该能满足你的调度需求。

例如:

  • 你希望触发器在2015年1月13日上午11:23:54准时触发,或是希望在那个时间点触发,然后再重复触发5次,每隔10秒一次。

使用案例:

  • 触发器 2018-09-27 10:27:00 定点触发,重复0次
private static SimpleTrigger getTrigger2() throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        //定义一个任务触发器
        return newTrigger()
                .withIdentity("job1", "group1")
                //定点触发
                .startAt(sdf.parse("2018-09-27 10:27:00"))
                .withSchedule(simpleSchedule()
                        .withIntervalInSeconds(2)

                        .withRepeatCount(0)
                ).build();

 }

注:startAt中的日期可以使用DateBuilder,示例,在指定时间延迟5秒执行

.startAt(DateBuilder.futureDate(5, DateBuilder.IntervalUnit.SECOND))

触发失败指令(待完善。。。)

执行常量如下:

MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY  
MISFIRE_INSTRUCTION_FIRE_NOW  
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT  
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT  
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT  
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT

触发指令设置

withMisfireHandlingInstructionFireNow
——以当前时间为触发频率立即触发执行
——执行至FinalTIme的剩余周期次数
——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到
——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值

withMisfireHandlingInstructionIgnoreMisfires
——以错过的第一个频率时间立刻开始执行
——重做错过的所有频率周期
——当下一次触发频率发生时间大于当前时间以后,按照Interval的依次执行剩下的频率
——共执行RepeatCount+1次

withMisfireHandlingInstructionNextWithExistingCount
——不触发立即执行
——等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数
——以startTime为基准计算周期频率,并得到FinalTime
——即使中间出现pause,resume以后保持FinalTime时间不变


withMisfireHandlingInstructionNowWithExistingCount
——以当前时间为触发频率立即触发执行
——执行至FinalTIme的剩余周期次数
——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到
——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值

withMisfireHandlingInstructionNextWithRemainingCount
——不触发立即执行
——等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数
——以startTime为基准计算周期频率,并得到FinalTime
——即使中间出现pause,resume以后保持FinalTime时间不变

withMisfireHandlingInstructionNowWithRemainingCount
——以当前时间为触发频率立即触发执行
——执行至FinalTIme的剩余周期次数
——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到
——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值

MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
——此指令导致trigger忘记原始设置的starttime和repeat-count
——触发器的repeat-count将被设置为剩余的次数
——这样会导致后面无法获得原始设定的starttime和repeat-count值

cronTrigger

使用场景:CronTrigger比SimpleTrigger更常用,当你需要一个基于日历般概念的作业调度器,而不是像SimpleTrigger那样精确指定间隔时间。

使用cronTrigger,你可以这样指定触发时间表例如每周五的中午,或是每周末的上午9:30,甚至是一月份每周一、三、五上午9:00到10:00之间每5分钟

CronTrigger也需要指定startTime让调度器生效,指定endTime让调度器终止。

cron表达式

Cron表达式实际上是由7个子表达式组成的字符串,这些子表达式用空格隔开,分别代表:

类型范围
0-60
0-60
小时0-23
月份中的天数0-31,但需要注意,有些月份如没有31
0-11,可以使用:JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC
星期中的天数1-7,可以使用: SUN,MON,TUE,WED,THU,FRI,SAT
年(可选)一般不用

符号介绍:

/ : - 如果你在分钟字段写“0/15”,这表示“每次从一小时中的第0分钟开始,每隔15分钟触发”, - 如果你在分钟字段上写“3/20”,这表示“每次从一小时中的第3分钟开始,每隔20分钟触发”——换句话说,这跟在分钟字段上指定“3,23,43”是一样的。

? : - 字符允许出现在月份中的天数和星期中的天数字段中。它一般用来指定“不关心的值”。 - 当你需要在这两个字段中的一个指定不确定的值是非常方便的,这个字符不能用在其他的字段中。

L : - 字符允许出现在月份中的天数和星期中的天数字段中 - “L”字符出现在月份中的天数字段中表示“每月的最后一天”——1月31日,平年的2月28日

w : - 字符用来指定给定日期的最近一个工作日(工作日指的是从周一到周五) - 如果你在月份中的天数字段的值指定为“15w”,这表示“离每月15号最近的工作日”。

'井' : - ”字符用来指定每月的第N个工作日 - 星期中的天数字段的值为“6#3”或是“FRI#3”表示“每月的第三个星期五”。

常用表达式案例

Cron案例1——仅仅表示每隔5分钟触发一次:"0 0/5 * * * ?"

Cron案例2——表示每隔5分钟,在过了10秒后触发一次(例如上午10:00:10,10:05:10等):"10 0/5 * * * ?"

Cron案例3——表示每个周三到周五,在上午10:30,11:30,12:30和13:30分触发:"0 30 10-13 ? * WED,FRI"

Cron案例4——表示每月从5号到20号,上午8时到10时之间的每半小时触发,注意这个触发器只在8:00,8:30,9:00和9:30分触发,上午10:00不会触发:"0 0/30 8-9 5,20 * ?"

注意有些调度需求因太复杂例如“上午9:00到10:00之间的每5分钟,下午1:00到10:00的每20分钟”,而不能用单一的触发器来表示。这种情况的解决方案是创建两个简单的触发器,将它们注册到调度器中去运行同一个作业任务。

代码实现(CronTrigger构建)

触发器,每天从的下午3:33 触发一次

    private static CronTrigger getTrigger5() throws ParseException {
        //定义一个任务触发器
        return newTrigger()
                .withIdentity("job1", "group1")
                .withSchedule(CronScheduleBuilder.cronSchedule("0 27 16  * * ?"))
                //或者下边这样写
                // .withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(15, 33))
                .forJob("job1", "group1")
                .build();
    }

注:CronScheduleBuilder默认提供了一些常用表达式实现,如下图,请自行尝试

<img src="https://ws2.sinaimg.cn/mw690/005AQjvJly1fw440fu2jnj31dw0fowkp.jpg" alt="image">

触发失败指令(待完善。。。)

CronTrigger的触发失败指令常量:

MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY  
MISFIRE_INSTRUCTION_DO_NOTHING  
MISFIRE_INSTRUCTION_FIRE_NOW  

触发指令设置:

withMisfireHandlingInstructionDoNothing
——不触发立即执行
——等待下次Cron触发频率到达时刻开始按照Cron频率依次执行

withMisfireHandlingInstructionIgnoreMisfires
——以错过的第一个频率时间立刻开始执行
——重做错过的所有频率周期后
——当下一次触发频率发生时间大于当前时间后,再按照正常的Cron频率依次执行

withMisfireHandlingInstructionFireAndProceed
——以当前时间为触发频率立刻触发一次执行
——然后按照Cron频率依次执行

暂停及恢复补全问题

问题介绍: - 1).执行暂停任务,重启后,在暂停期间没执行的任务又TM给补上了 - 2).服务器挂了,重启后,在暂停期间没执行的任务又TM给补上了

解决方式:

  • 1).先设置触发失败指令
   cronSchedule(cronExpression).withMisfireHandlingInstructionFireAndProceed()
   或者
   cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing()

设置完成重新启动发现没软用

  • 2).配置参数 quartz.properties中
#这个时间大于10000(10秒)会导致MISFIRE_INSTRUCTION_DO_NOTHING不起作用。
org.quartz.jobStore.misfireThreshold = 5000

解释:

misfireThreshold表示实际执行的时间与下一次应该执行时间之间的差值,超过这个差值就不会执行,低于这个差值就会执行。 比如我每3秒执行一次,misfireThreshold=6000,当你暂停低于6秒内,它会弥补执行,超过6秒,它就不再弥补执行了。

参见:

(quartz暂停及恢复任务解决恢复时一咕噜把未执行的全补回来的问题)[http://www.itboth.com/d/mqE3In/quartz-java]<br> (quartz 失败触发指令)[http://www.voidcn.com/article/p-yvvrqdrt-ku.html]<br>

转载于:https://my.oschina.net/ahusky/blog/2243732

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值