03.Quartz 定时任务-Job 和 JobDetail

家住魔仙堡 提交于 2019-11-28 18:18:46

Quartz 中自定义Job实现方式很简单, 只需要实现Job接口并实现其execute方法即可. 将自定义job添加到调度列表时, 需将Job封装称JobDetail, 并设置job的标识符等信息. 需要特别注意的是, 当定时任务触发时, 调度器Scheduler 会获取JobDetail中关联的Job类信息, 并创建Job实例, 然后执行其execute方法. 当execute 方法执行完后, 会丢弃新创建的Job实例, 任其等待java 的垃圾回收.

1. 核心概念

  • Job: 用于定义定时任务触发时的执行体, 即定时任务要处理的业务逻辑. 需要实现Job接口, 并重写execute接口
  • JobDetail: 用于定义Job的基础信息, 如job的标识符, 描述等. 通常借助于JobBuilder 快速创建.
  • JobBuilder: 快捷构建JobDetail 的工具类

1.1 Job 接口定义

自定义job时需要实现Job接口, 并重写job的唯一方法execute方法.

package org.quartz;

public interface Job {
    void execute(JobExecutionContext context) throws JobExecutionException;
}

1.2 JobBuilder 常用API

JobBuilder 配置JobDetail属性的API采用链式编程风格, 方法前面返回均为该对象, 使用起来更方便简洁.

方法签名 方法描述
public JobBuilder withIdentity(String name) 设置job标识符ID, 分组名为默认DEFAULT
public JobBuilder withIdentity(String name, String group) 设置job标识符ID
public JobBuilder withIdentity(JobKey jobKey) 设置job标识符ID
public JobBuilder withDescription(String jobDescription) 设置job描述信息
public JobBuilder requestRecovery(boolean jobShouldRecover) 设置当出现故障转移或恢复情况时, 是否重新执行job. 默认为false
public JobBuilder storeDurably(boolean jobDurability) 设置当没有Trigger关联job时, 是否继续持久化job. 设置为false时, 会删除job. 当执行scheduler.unscheduleJob(triggerKey)方法时会设计到这种情况
public JobBuilder usingJobData(String dataKey, String/Integer/… value) 添加传递数据, 当任务触发时, 在execute方法中可以获取
public JobBuilder setJobData(JobDataMap newJobDataMap) 设置传递数据
public JobDetail build() 返回JobDetail 对象, 实际返回的时JobDetail对象

1.3 定时任务的并发性和JobDat更新传递性

  • @DisallowConcurrentExecution: 默认情况下, quartz的定时任务是可以并发执行的, 也就是说如果本次定时任务调度还没有执行完(耗时比较长), 又到了下一个触发时间点, 那么会再次创建一个Job实例, 然后执行execute方法. quartz 提供了注解@DisallowConcurrentExecution, 用于禁止定时任务并发执行. 但是需要注意的是, 虽然@DisallowConcurrentExecution 注解时添加到自定义Job上的, 但是并发性时控制在JobDetail级别的. 也就是说, 如果一个Job配置了多个JobDetail, 那么多个JobDetail 之间可以并发执行, 但是单个JobDetail 不能并发执行.
  • @PersistJobDataAfterExecution: 当job 正常执行没有抛出异常时, 更新Job存储在JobDataMap中数据, 以便下次触发时获取. 官方建议使用次注解时, 也同时设置@DisallowConcurrentExecution, 因为在允许并发执行的情况下, 可能到时参数不能按预期传递.

2. 自定义Job

2.1 自定义job实例

// 添加@DisallowConcurrentExecution注解后, 则表示此定时任务不能并发执行
// @DisallowConcurrentExecution
public class HelloJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 获取job定义
        JobDetail jobDetail = context.getJobDetail();

        // 获取job数据
        JobDataMap jobDataMap = jobDetail.getJobDataMap();

        // 获取Trigger
        Trigger trigger = context.getTrigger();

        //....

        System.out.println(LocalDateTime.now() + "-" + getClass().getName() + "-hello");

    }
}

2.2 构建JobDetail

  • 每个定时任务都需要被定义(设置标识符, 描述等基本信息, 包装成JobDetial)之后才能被调度
  • quartz提供了JobBuilder 来便捷地创建JobDetail
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)   // 指定job执行体
            .withIdentity("hello","group1")         // 设置job的唯一标识符
            .withDescription("my first job")        // 设置job 描述信息
            .storeDurably(true)                     // 设置当没有Trigger关联job时是否继续存储job. 设置为false时, 会同时删除job; 默认为false
            .requestRecovery(true)                  // 在程序恢复或故障转移时, 是否重新执行job, 默认为false
            .usingJobData("author", "zongf")        // 设置携带数据, 在job触发时可以获取
            .usingJobData("year", "2019")
            .build();

2.3 添加调度

# 添加调度任务, 根据job的名称和分组判断, 如果job已经存在时, 抛出异常
scheduler.scheduleJob(jobDetail, trigger);

# 添加调度任务, 如果job已经存在, 则覆盖更新jo
scheduler.scheduleJob(job, triggerSet, true);

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!