Quartz认知篇 - 初识分布式任务调度Quartz

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

定时任务的使用场景

在遇到如下几种场景可以考虑使用定时任务来解决

  • 某个时刻或者时间间隔执行任务
  • 批量数据进行处理
  • 对两个动作进行解耦

Quartz

介绍

Quartz 是一个特性丰富的、开源的任务调度库几乎可以嵌入所有的 Java 程序包括很小的独立应用程序到大型商业系统。Quartz 可以用来创建成百上千的简单的或者复杂的任务并且这些任务可以作为执行任何事情的标准 Java 组件。Quartz 拥有很多企业级别的特性包括支持 JTA 事务和集群。

Quartz is a richly featured, open source job scheduling library that can be integrated within virtually any Java application - from the smallest stand-alone application to the largest e-commerce system. Quartz can be used to create simple or complex schedules for executing tens, hundreds, or even tens-of-thousands of jobs; jobs whose tasks are defined as standard Java components that may execute virtually anything you may program them to do. The Quartz Scheduler includes many enterprise-class features, such as support for JTA transactions and clustering.

体系结构

在这里插入图片描述

配置触发的规则

定义要执行的任务代码/脚本

集中管理配置

并发执行任务互不干扰

调度器控制任务的生命周期

可以集成 Spring、Spring Boot

任务

可以实现 Job 接口来定义一个任务然后重写它的 execute 方法来定义任务执行的逻辑。

public class MyJob implements Job {

    private static final Logger LOGGER = LoggerFactory.getLogger(MyJob.class);

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        LOGGER.info(simpleDateFormat.format(new Date()) + ", 任务1执行了, " + jobDataMap.getString("hello"));
    }
}

而调度器的调度方法需要指定一个 JobDetail即任务明细。JobDetail 可以通过 JobBuilder 的相关方法进行实例化。

JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
        .withIdentity("myJob", "my-job-group")
        .usingJobData("hello", "tom")
        .usingJobData("hi", "selina")
        .build();

接下来看下 JobBuilder 中定义的一些比较重要的方法。

1、newJob 方法

实例化 JobBuilder(可以指定一个任务

public static JobBuilder newJob() {
  return new JobBuilder();
}

public static JobBuilder newJob(Class<? extends Job> jobClass) {
  JobBuilder b = new JobBuilder();
  b.ofType(jobClass);
  return b;
}

2、ofType 方法

指定任务

public JobBuilder ofType(Class<? extends Job> jobClazz) {
  this.jobClass = jobClazz;
  return this;
}

3、withIdentity 方法

指定任务的名字和组

public JobBuilder withIdentity(String name) {
  key = new JobKey(name, null);
  return this;
}

public JobBuilder withIdentity(String name, String group) {
  key = new JobKey(name, group);
  return this;
}

public JobBuilder withIdentity(JobKey jobKey) {
  this.key = jobKey;
  return this;
}

4、withDescription 方法

指定任务的描述

public JobBuilder withDescription(String description) {
  this.description = description;
  return this;
}

5、requestRecovery 方法

指定任务遇到“recovery”或者“fail-over”情形是否应该重新执行

public JobBuilder requestRecovery() {
  this.shouldRecover = true;
  return this;
}

public JobBuilder requestRecovery(boolean jobShouldRecover) {
  this.shouldRecover = jobShouldRecover;
  return this;
}

6、storeDurably 方法

指定任务是否应该持久化

public JobBuilder storeDurably() {
  this.durability = true;
  return this;
}

public JobBuilder storeDurably(boolean jobDurability) {
  this.durability = jobDurability;
  return this;
} 

7、usingJobData 方法

添加一组键值对到 JobDetail 的 JobDataMap 属性中

public JobBuilder usingJobData(String dataKey, String value) {
  jobDataMap.put(dataKey, value);
  return this;
}

public JobBuilder usingJobData(String dataKey, Integer value) {
  jobDataMap.put(dataKey, value);
  return this;
}

public JobBuilder usingJobData(String dataKey, Long value) {
  jobDataMap.put(dataKey, value);
  return this;
}

public JobBuilder usingJobData(String dataKey, Float value) {
  jobDataMap.put(dataKey, value);
  return this;
}

public JobBuilder usingJobData(String dataKey, Double value) {
  jobDataMap.put(dataKey, value);
  return this;
}

public JobBuilder usingJobData(String dataKey, Boolean value) {
  jobDataMap.put(dataKey, value);
  return this;
}

public JobBuilder usingJobData(JobDataMap newJobDataMap) {
  jobDataMap.putAll(newJobDataMap);
  return this;
}

8、setJobData 方法

覆盖 JobDetail 的 JobDataMap 属性

public JobBuilder setJobData(JobDataMap newJobDataMap) {
  jobDataMap = newJobDataMap;
  return this;
}

9、build 方法

构建 JobDetailImpl 实例

public JobDetail build() {

    JobDetailImpl job = new JobDetailImpl();
    
    job.setJobClass(jobClass);
    job.setDescription(description);
    if(key == null)
        key = new JobKey(Key.createUniqueName(null), null);
    job.setKey(key); 
    job.setDurability(durability);
    job.setRequestsRecovery(shouldRecover);
    
    
    if(!jobDataMap.isEmpty())
        job.setJobDataMap(jobDataMap);
    
    return job;
}

触发器

任务触发的规则。

调度器的调度方法需要指定一个 Trigger 实例即触发器。可以通过 TriggerBuilder 的相关方法构建一个 Trigger 实例。

Trigger trigger = TriggerBuilder.newTrigger()
        .withIdentity("myTrigger", "my-trigger-group")
        .startNow()
        .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                .withIntervalInSeconds(5)
                .repeatForever())
        .build();

接下来看下 TriggerBuilder 定义的一些比较重要的方法。

1、newTrigger 方法

构建 TriggerBuilder 实例

public static TriggerBuilder<Trigger> newTrigger() {
  return new TriggerBuilder<Trigger>();
}

2、withIdentity 方法

设置触发器的名字和组名

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

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

public TriggerBuilder<T> withIdentity(TriggerKey triggerKey) {
  this.key = triggerKey;
  return this;
}

3、withDescription 方法

设置触发器的描述

public TriggerBuilder<T> withDescription(String triggerDescription) {
  this.description = triggerDescription;
  return this;
}

4、withPriority 方法

设置触发器的优先级(如果有多个启动时间相同的触发器根据触发器的优先级由大到小的顺序进行启动

public TriggerBuilder<T> withPriority(int triggerPriority) {
  this.priority = triggerPriority;
  return this;
}

5、modifiedByCalendar 方法

设置应用到该触发器调度的 Calendar 的名字

public TriggerBuilder<T> modifiedByCalendar(String calName) {
  this.calendarName = calName;
  return this;
}

6、startAt 方法

设置触发器的开始时间

public TriggerBuilder<T> startAt(Date triggerStartTime) {
  this.startTime = triggerStartTime;
  return this;
}

7、startNow 方法

设置触发器立即开始

public TriggerBuilder<T> startNow() {
  this.startTime = new Date();
  return this;
}

8、endAt 方法

设置触发器的结束时间

public TriggerBuilder<T> endAt(Date triggerEndTime) {
  this.endTime = triggerEndTime;
  return this;
}

9、withSchedule 方法

设置用于触发器调度的 ScheduleBuilder

public <SBT extends T> TriggerBuilder<SBT> withSchedule(ScheduleBuilder<SBT> scheduleBuilder) {
  this.scheduleBuilder = scheduleBuilder;
  returnt (TriggerBuilder<SBT>) this;
}

10、forJob 方法

设置触发器关联的任务

public TriggerBuilder<T> forJob(JobKey jobKey) {
  this.jobKey = jobKey;
  return this;
}

public TriggerBuilder<T> forJob(String jobName) {
  this.jobKey = new JobKey(jobName, null);
  retun this;
}

public TriggerBuilder<T> forJob(String jobName, String jobGroup) {
  this.jobKey = new JobKey(jobName, jobGroup);
  return this;
}

public TriggerBuilder<T> forJob(JobDetail jobDetail) {
  JobKey k = jobDetail.getKey();
  if (k.getName() == null) {
    throw new IllegalArgumentException("The given job has not yet had a name assigned to it.");
  }
  this.jobKey = k;
  return this;
}

11、usingJobData 方法

添加一组键值对到触发器的 JobDataMap 属性中

public TriggerBuilder<T> usingJobData(String dataKey, String value) {
  jobDataMap.put(dataKey, value);
  return this;
}

public TriggerBuilder<T> usingJobData(String dataKey, String value) {
  jobDataMap.put(dataKey, value);
  return this;
}

public TriggerBuilder<T> usingJobData(String dataKey, Integer value) {
  jobDataMap.put(dataKey, value);
  return this;
}

public TriggerBuilder<T> usingJobData(String dataKey, Long value) {
  jobDataMap.put(dataKey, value);
  return this;
}

public TriggerBuilder<T> usingJobData(String dataKey, Float value) {
  jobDataMap.put(dataKey, value);
  return this;
}

public TriggerBuilder<T> usingJobData(String dataKey, Double value) {
  jobDataMap.put(dataKey, value);
  return this;
}

public TriggerBuilder<T> usingJobData(String dataKey, Boolean value) {
  jobDataMap.put(dataKey, value);
  return this;
}

public TriggerBuilder<T> usingJobData(JobDataMap newJobDataMap) {
  for(String dataKey: jobDataMap.keySet()) {
    newJobDataMap.put(dataKey, jobDataMap.get(dataKey));
  }
  jobDataMap = newJobDataMap; 
  return this;
}

12、build 方法

构建具体的 Trigger 实例

public T build() {

    if(scheduleBuilder == null)
        scheduleBuilder = SimpleScheduleBuilder.simpleSchedule();
    MutableTrigger trig = scheduleBuilder.build();
    
    trig.setCalendarName(calendarName);
    trig.setDescription(description);
    trig.setStartTime(startTime);
    trig.setEndTime(endTime);
    if(key == null)
        key = new TriggerKey(Key.createUniqueName(null), null);
    trig.setKey(key); 
    if(jobKey != null)
        trig.setJobKey(jobKey);
    trig.setPriority(priority);
    
    if(!jobDataMap.isEmpty())
        trig.setJobDataMap(jobDataMap);
    
    return (T) trig;
}

SimpleTrigger

时间间隔执行n次(时分秒

1、simpleSchedule 方法

构建 SimpleScheduleBuilder 实例

public static SimpleScheduleBuilder simpleSchedule() {
    return new SimpleScheduleBuilder();
}

2、repeat…Forever 方法

指定时间间隔永久重复执行

// 指定每隔一分钟永久重复执行
public static SimpleScheduleBuilder repeatMinutelyForever() {
    return simpleSchedule()
        .withIntervalInMinutes(1)
        .repeatForever();
}

// 指定每隔多少分钟永久重复执行
public static SimpleScheduleBuilder repeatMinutelyForever(int minutes) {
    return simpleSchedule()
        .withIntervalInMinutes(minutes)
        .repeatForever();
}

// 指定每隔一秒永久重复执行
public static SimpleScheduleBuilder repeatSecondlyForever() {
    return simpleSchedule()
        .withIntervalInSeconds(1)
        .repeatForever();
}

// 指定每隔多少秒永久重复执行
public static SimpleScheduleBuilder repeatSecondlyForever(int seconds) {
    return simpleSchedule()
        .withIntervalInSeconds(seconds)
        .repeatForever();
}

// 指定每隔一小时永久重复执行
public static SimpleScheduleBuilder repeatHourlyForever() {
    return simpleSchedule()
        .withIntervalInHours(1)
        .repeatForever();
}

// 指定每隔多少小时永久重复执行
public static SimpleScheduleBuilder repeatHourlyForever(int hours) {
    return simpleSchedule()
        .withIntervalInHours(hours)
        .repeatForever();
}

3、repeat…ForTotalCount 方法

指定时间间隔重复执行直到指定次数

// 每隔一分钟重复执行一次直到指定次数
public static SimpleScheduleBuilder repeatMinutelyForTotalCount(int count) {
    if(count < 1)
        throw new IllegalArgumentException("Total count of firings must be at least one! Given count: " + count);
    return simpleSchedule()
        .withIntervalInMinutes(1)
        .withRepeatCount(count - 1);
}

// 每隔多少分钟重复执行一次直到指定次数
public static SimpleScheduleBuilder repeatMinutelyForTotalCount(int count, int minutes) {
    if(count < 1)
        throw new IllegalArgumentException("Total count of firings must be at least one! Given count: " + count);
    return simpleSchedule()
        .withIntervalInMinutes(minutes)
        .withRepeatCount(count - 1);
}

// 每隔一秒重复执行一次直到指定次数
public static SimpleScheduleBuilder repeatSecondlyForTotalCount(int count) {
    if(count < 1)
        throw new IllegalArgumentException("Total count of firings must be at least one! Given count: " + count);
    return simpleSchedule()
        .withIntervalInSeconds(1)
        .withRepeatCount(count - 1);
}

// 每隔多少秒重复执行一次直到指定次数
public static SimpleScheduleBuilder repeatSecondlyForTotalCount(int count, int seconds) {
    if(count < 1)
        throw new IllegalArgumentException("Total count of firings must be at least one! Given count: " + count);
    return simpleSchedule()
        .withIntervalInSeconds(seconds)
        .withRepeatCount(count - 1);
}

// 每隔一小时重复执行一次直到指定次数
public static SimpleScheduleBuilder repeatHourlyForTotalCount(int count) {
    if(count < 1)
        throw new IllegalArgumentException("Total count of firings must be at least one! Given count: " + count);
    return simpleSchedule()
        .withIntervalInHours(1)
        .withRepeatCount(count - 1);
}

// 每隔多少小时重复执行一次直到指定次数
public static SimpleScheduleBuilder repeatHourlyForTotalCount(int count, int hours) {
    if(count < 1)
        throw new IllegalArgumentException("Total count of firings must be at least one! Given count: " + count);
    return simpleSchedule()
        .withIntervalInHours(hours)
        .withRepeatCount(count - 1);
}

4、withInterval… 方法

指定时间间隔执行一次

// 每隔多少毫秒执行一次
public SimpleScheduleBuilder withIntervalInMilliseconds(long intervalInMillis) {
    this.interval = intervalInMillis;
    return this;
}

// 每隔多少秒执行一次
public SimpleScheduleBuilder withIntervalInSeconds(int intervalInSeconds) {
    this.interval = intervalInSeconds * 1000L;
    return this;
}

// 每隔多少分钟执行一次
public SimpleScheduleBuilder withIntervalInMinutes(int intervalInMinutes) {
    this.interval = intervalInMinutes * DateBuilder.MILLISECONDS_IN_MINUTE;
    return this;
}

// 每隔多少小时执行一次
public SimpleScheduleBuilder withIntervalInHours(int intervalInHours) {
    this.interval = intervalInHours * DateBuilder.MILLISECONDS_IN_HOUR;
    return this;
}

5、withRepeatCount 方法

指定重复执行的次数

public SimpleScheduleBuilder withRepeatCount(int triggerRepeatCount) {
    this.repeatCount = triggerRepeatCount;
    return this;
}

6、repeatForever 方法

指定永久重复执行

public SimpleScheduleBuilder repeatForever() {
    this.repeatCount = SimpleTrigger.REPEAT_INDEFINITELY;
    return this;
}

7、withMisfire 方法

设置触发器错过启动时间的补偿策略

public SimpleScheduleBuilder withMisfireHandlingInstructionIgnoreMisfires() {
    misfireInstruction = Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY;
    return this;
}

public SimpleScheduleBuilder withMisfireHandlingInstructionFireNow() {
    misfireInstruction = SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW;
    return this;
}

public SimpleScheduleBuilder withMisfireHandlingInstructionNextWithExistingCount() {
    misfireInstruction = SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT;
    return this;
}

public SimpleScheduleBuilder withMisfireHandlingInstructionNextWithRemainingCount() {
    misfireInstruction = SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT;
    return this;
}

public SimpleScheduleBuilder withMisfireHandlingInstructionNowWithExistingCount() {
    misfireInstruction = SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT;
    return this;
}

public SimpleScheduleBuilder withMisfireHandlingInstructionNowWithRemainingCount() {
    misfireInstruction = SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT;
    return this;
}

CalendarIntervalTrigger

时间间隔执行一次(年月周日时分秒

1、calendarIntervalSchedule 方法

构建 CalendarIntervalScheduleBuilder 实例

public static CalendarIntervalScheduleBuilder calendarIntervalSchedule() {
  return new CalendarIntervalScheduleBuilder();
}

2、withInterval…方法

每隔多少时间间隔执行一次

// 每隔多少时间单位执行一次
public CalendarIntervalScheduleBuilder withInterval(int timeInterval, IntervalUnit unit) {
    if(unit == null)
        throw new IllegalArgumentException("TimeUnit must be specified.");
    validateInterval(timeInterval);
    this.interval = timeInterval;
    this.intervalUnit = unit;
    return this;
}

// 每隔多少秒执行一次
public CalendarIntervalScheduleBuilder withIntervalInSeconds(int intervalInSeconds) {
    validateInterval(intervalInSeconds);
    this.interval = intervalInSeconds;
    this.intervalUnit = IntervalUnit.SECOND;
    return this;
}

// 每隔多少分钟执行一次
public CalendarIntervalScheduleBuilder withIntervalInMinutes(int intervalInMinutes) {
    validateInterval(intervalInMinutes);
    this.interval = intervalInMinutes;
    this.intervalUnit = IntervalUnit.MINUTE;
    return this;
}

// 每隔多少小时执行一次
public CalendarIntervalScheduleBuilder withIntervalInHours(int intervalInHours) {
    validateInterval(intervalInHours);
    this.interval = intervalInHours;
    this.intervalUnit = IntervalUnit.HOUR;
    return this;
}

// 每隔多少天执行一次
public CalendarIntervalScheduleBuilder withIntervalInDays(int intervalInDays) {
    validateInterval(intervalInDays);
    this.interval = intervalInDays;
    this.intervalUnit = IntervalUnit.DAY;
    return this;
}

// 每隔多少周执行一次
public CalendarIntervalScheduleBuilder withIntervalInWeeks(int intervalInWeeks) {
    validateInterval(intervalInWeeks);
    this.interval = intervalInWeeks;
    this.intervalUnit = IntervalUnit.WEEK;
    return this;
}

// 每隔多少月执行一次
public CalendarIntervalScheduleBuilder withIntervalInMonths(int intervalInMonths) {
    validateInterval(intervalInMonths);
    this.interval = intervalInMonths;
    this.intervalUnit = IntervalUnit.MONTH;
    return this;
}

// 每隔多少年执行一次
public CalendarIntervalScheduleBuilder withIntervalInYears(int intervalInYears) {
    validateInterval(intervalInYears);
    this.interval = intervalInYears;
    this.intervalUnit = IntervalUnit.YEAR;
    return this;
}

3、withMisfire… 方法

设置触发器错过启动时间的补偿策略

public CalendarIntervalScheduleBuilder withMisfireHandlingInstructionIgnoreMisfires() {
    misfireInstruction = Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY;
    return this;
}

public CalendarIntervalScheduleBuilder withMisfireHandlingInstructionDoNothing() {
    misfireInstruction = CalendarIntervalTrigger.MISFIRE_INSTRUCTION_DO_NOTHING;
    return this;
}

public CalendarIntervalScheduleBuilder withMisfireHandlingInstructionFireAndProceed() {
    misfireInstruction = CalendarIntervalTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW;
    return this;
}

4、inTimeZone 方法

设置时区

public CalendarIntervalScheduleBuilder inTimeZone(TimeZone timezone) {
    this.timeZone = timezone;
    return this;
}

5、build 方法

构建 CalendarIntervalTriggerImpl 实例

@Override
public MutableTrigger build() {
    CalendarIntervalTriggerImpl st = new CalendarIntervalTriggerImpl();
    st.setRepeatInterval(interval);
    st.setRepeatIntervalUnit(intervalUnit);
    st.setMisfireInstruction(misfireInstruction);
    st.setTimeZone(timeZone);
    st.setPreserveHourOfDayAcrossDaylightSavings(preserveHourOfDayAcrossDaylightSavings);
    st.setSkipDayIfHourDoesNotExist(skipDayIfHourDoesNotExist);
    return st;
}

DailyTimeIntervalTrigger

CronTrigger

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6