Quartz源码角度分析以及Springboot中的案列实现

基础

若要明白 Quartz 怎么用,首先要了解 Job (任务)、JobDetail (任务信息)、Trigger (触发器)和Scheduler (调度器)这 4 个核心的概念。

Job

job 是一个接口,只定义一个方法execute(JobExecutionContext context),在实现接口的 execute 方法中编写所需要定时执行的 Job(任务),JobExecutionContext 类提供了调度应用的一些信息。Job 运行时的信息保存在 JobDataMap 实例中。

  • Job源码:
package org.quartz;

public interface Job {
    void execute(JobExecutionContext var1) throws JobExecutionException;
}
  • JobExecutionContext源码:
package org.quartz;

import java.util.Date;

public interface JobExecutionContext {
    Scheduler getScheduler();     //调度器, 装载着任务和触发器

    Trigger getTrigger();         //触发器,触发 Job 执行的时间触发规则

    Calendar getCalendar();

    boolean isRecovering();

    TriggerKey getRecoveringTriggerKey() throws IllegalStateException;

    int getRefireCount();

    JobDataMap getMergedJobDataMap();

    JobDetail getJobDetail();   //Job实现类

    Job getJobInstance();      //job

    Date getFireTime();

    Date getScheduledFireTime();

    Date getPreviousFireTime();

    Date getNextFireTime();

    String getFireInstanceId();

    Object getResult();

    void setResult(Object var1);

    long getJobRunTime();

    void put(Object var1, Object var2);

    Object get(Object var1);
}

JobDetail

Quartz 每次调度 Job 时,都重新创建一个 Job 实例,所以它不直接接受一个 Job 的实例,相反它接收一个 Job 实现类(JobDetail ,描述 Job 的实现类及其他相关的静态信息,如 Job 名字、描述、关联监听器等信息),以便运行时通过 newInstance() 的反射机制实例化 Job

public interface JobDetail extends Serializable, Cloneable {
    JobKey getKey();

    String getDescription();

    Class<? extends Job> getJobClass();

    JobDataMap getJobDataMap();

    boolean isDurable();

    boolean isPersistJobDataAfterExecution();

    boolean isConcurrentExectionDisallowed();

    boolean requestsRecovery();

    Object clone();

    JobBuilder getJobBuilder();
}

Trigger

描述触发 Job 执行的时间触发规则。主要有 SimpleTriggerCronTrigger 这两个子类。
当且仅当需调度一次或者以固定时间间隔周期执行调度,SimpleTrigger 是最适合的选择;而 CronTrigger 则可以通过 Cron 表达式定义出各种复杂时间规则的调度方案,如工作日周一到周五的 15:00~16:00 执行调度等。

CronTrigger 源码:

package org.quartz;

import java.util.TimeZone;

public interface CronTrigger extends Trigger {
    long serialVersionUID = -8644953146451592766L;
    int MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1;
    int MISFIRE_INSTRUCTION_DO_NOTHING = 2;

    String getCronExpression();

    TimeZone getTimeZone();

    String getExpressionSummary();

    TriggerBuilder<CronTrigger> getTriggerBuilder();
}

Scheduler

调度器就相当于一个容器,装载着任务和触发器。 该类是一个接口,代表一个 Quartz 的独立运行容器,TriggerJobDetail 可以注册到 Scheduler 中,两者在 Scheduler 中拥有各自的组及名称,组及名称是 Scheduler 查找定位容器中某一对象的依据,Trigger 的组及名称必须唯一, JobDetail 的组和名称也必须唯一(但可以和 Trigger 的组和名称相同,因为它们是不同类型的)。Scheduler 定义了多个接口方法,允许外部通过组及名称访问和控制容器中 TriggerJobDetail

Scheduler 部分源码:

package org.quartz;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.quartz.Trigger.TriggerState;
import org.quartz.impl.matchers.GroupMatcher;
import org.quartz.spi.JobFactory;

public interface Scheduler {
    String DEFAULT_GROUP = "DEFAULT";
    String DEFAULT_RECOVERY_GROUP = "RECOVERING_JOBS";
    String DEFAULT_FAIL_OVER_GROUP = "FAILED_OVER_JOBS";
    String FAILED_JOB_ORIGINAL_TRIGGER_NAME = "QRTZ_FAILED_JOB_ORIG_TRIGGER_NAME";
    String FAILED_JOB_ORIGINAL_TRIGGER_GROUP = "QRTZ_FAILED_JOB_ORIG_TRIGGER_GROUP";
    String FAILED_JOB_ORIGINAL_TRIGGER_FIRETIME_IN_MILLISECONDS = "QRTZ_FAILED_JOB_ORIG_TRIGGER_FIRETIME_IN_MILLISECONDS_AS_STRING";
    String FAILED_JOB_ORIGINAL_TRIGGER_SCHEDULED_FIRETIME_IN_MILLISECONDS = "QRTZ_FAILED_JOB_ORIG_TRIGGER_SCHEDULED_FIRETIME_IN_MILLISECONDS_AS_STRING";

    //job和trigger结合
    Date rescheduleJob(TriggerKey var1, Trigger var2) throws SchedulerException;
    //更新job和trigger结合
    Date rescheduleJob(TriggerKey var1, Trigger var2) throws SchedulerException;
    //立即执行任务
    void triggerJob(JobKey var1, JobDataMap var2) throws SchedulerException;
    //暂停任务
    void pauseJob(JobKey var1) throws SchedulerException;
    //恢复任务
    void resumeJob(JobKey var1) throws SchedulerException;
    //删除定时任务
    boolean deleteJob(JobKey var1) throws SchedulerException;

    //...
}

关联

如下图:

Job 为作业的接口,为任务调度的对象;JobDetail 用来描述 Job 的实现类及其他相关的静态信息;Trigger 做为作业的定时管理工具,一个 Trigger 只能对应一个作业实例,而一个作业实例可对应多个触发器;Scheduler 做为定时任务容器,是 quartz 最上层的东西,它提携了所有触发器和作业,使它们协调工作,每个 Scheduler 都存有 JobDetail 和 Trigger 的注册,一个 Scheduler 中可以注册多个 JobDetail 和多个 Trigger。

Spring Boot 和 Quartz

添加依赖

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-quartz</artifactId>
    </dependency>

新建Job

首先定义一个 Job 需要继承QuartzJobBeanQuartzJobBean继承了Job接口, 示例中 Job 定义一个变量 Name,用于在定时执行的时候传入。

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

/**
 *job
 */
public class SampleJob extends QuartzJobBean {

    private String name;

    public void setName(String name) {
        this.name = name;
    }

    @Override
    protected void executeInternal(JobExecutionContext context)
            throws JobExecutionException {
        System.out.println(String.format("Hello %s!", this.name));
    }

}

JobDetail和 JobTrigger 和 scheduleBuilder

import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SampleScheduler {

    @Bean
    public JobDetail sampleJobDetail() {
        return JobBuilder.newJob(SampleJob.class).withIdentity("sampleJob")
                .usingJobData("name", "World").storeDurably().build();
    }

    @Bean
    public Trigger sampleJobTrigger() {
        SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
                .withIntervalInSeconds(2).repeatForever();

        return TriggerBuilder.newTrigger().forJob(sampleJobDetail())
                .withIdentity("sampleTrigger").withSchedule(scheduleBuilder).build();
    }
}

程序入口main


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class QuartzApplication {

    public static void main(String[] args) {
        SpringApplication.run(QuartzApplication.class, args);
    }
}

效果图

每隔2秒执行一把job。

猜你喜欢

转载自blog.csdn.net/She_lock/article/details/81700571
今日推荐