美文网首页程序员Java 杂谈
Quartz设计原理详解(多图)

Quartz设计原理详解(多图)

作者: 黄大海 | 来源:发表于2018-12-21 15:10 被阅读12次

定时任务是日常开发中非常常见的功能。

对于简单的任务处理Spring的@Scheduled非常好用。
如果处理更复杂的情况,比如需要宕机恢复或者集群调度,那么Quartz是个不错的轻量级方案。
一些重量级的第三方任务调度系统也是基于Quartz扩展的,比如XXL-JOB

Quartz的模块

Quartz模块.png
  • Trigger定义了何时触发任务,主要是两种SimpleTrigger和CronTigger,其他Tigger基本都可以通过这两种实现。Trigger还可以定义错过的任务如何处理。下表是说明:


    trigger.jpeg
  • Calendar与Trigger相反,Calendar定义哪些时间是特例,不能执行任务。Calendar的优先级高于Trigger。HolidayCalendar比较常用,定义了哪些节日是特殊情况。


    calendar.jpeg
  • Job 负责定义任务所处理的逻辑,实现类需要实现org.quartz.Job接口

public interface Job {
    void execute(JobExecutionContext context) throws JobExecutionException;
}
  • 通过抛出JobExecutionException可以强制控制任务后续处理
public class JobExecutionException extends SchedulerException {
    private boolean refire = false;//true: 重新执行任务(不会触发下一次)
    private boolean unscheduleTrigg = false;//true: 直接标记Trigger完成
    private boolean unscheduleAllTriggs = false;//true: 直接标记所有和Job相关的Trigger都已经完成
}
  • Stateful Job。不同于一般的无状态任务,可以同时执行。有状态任务不能同时执行,而且需要保存状态。根据需要给可以Job类添加@PersistJobDataAfterExecution 或 @DisallowConcurrentExecution
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public interface StatefulJob extends Job {
}
  • JobDetail 保存Job的元信息,包括类定义和设置。
  • SchedulerFactory负责初始化,读取配置文件,然后创建Scheduler
  • Scheduler是中枢调度器,负责管理Trigger/JobDetail和3个调度线程
    1. QuartzSchedulerThread 主调度线程


      调度任务主流程 (1).png
  1. MisfireHandler 错失触发的任务恢复线程,。更新Trigger的触发时间。
  2. ClusterManager 集群协调线程。定期心跳,自动recover。同主程序中的recover。

SpringBoot2.0集成Quartz

从boot2.0开始,增加了对Quartz的自动装配,以前需要自己处理。
以集群配置为例,最基本的操作是这样的:

  • Maven依赖
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>
  • 编写具体的job
    public class TestJob extends QuartzJobBean {
        @Override
        protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
            System.out.println("Test job executed.");
        }
    }
  • 定义JobDetail, 把Job的class类型传入。Spring自动处理
    @Bean
    public JobDetail testJob(){
        return JobBuilder
                .newJob(TestJob.class)
                .withIdentity("TestJob")
                .storeDurably()
                .requestRecovery()
                .build();
    }
  • 定义Trigger, 通过Key关联JobDetail。Spring 自动处理。
    @Bean
    public Trigger testTrigger(){
        return TriggerBuilder.newTrigger()
            .withIdentity("TestTrigger")
            .forJob("TestJob")
            .withSchedule(CronScheduleBuilder
                    .cronSchedule("0/6 * * * * ? ")
                    .withMisfireHandlingInstructionDoNothing())
            .build();
    }
  • 如果需要不同的数据库,定义一个@Primary主库,和一个@QuartzDataSource quartz专用库
    @Bean
    @Primary
    @ConfigurationProperties(prefix="spring.datasource")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }
    
    @Bean
    @QuartzDataSource
    @ConfigurationProperties(prefix="spring.datasource.quartz")
    public DataSource quartzDataSource() {
        return DataSourceBuilder.create().build();
    }
  • application.properties 都有默认配置,第一行启用数据库,后面两行是cluster功能
spring.quartz.job-store-type=jdbc
spring.quartz.org.quartz.scheduler.instanceId = AUTO
spring.quartz.org.quartz.jobStore.isClustered = true
  • 虽然Spring提供了自动建库的功能,但是第一次建完之后需要改成never
spring.quartz.jdbc.initializeSchema=ALWAYS
#spring.quartz.jdbc.initializeSchema=NEVER
  • 手动建库可以从官网下载的全家桶,或者Jar包中获得

    1. 全家桶:{dir}/docs/dbTables/tables_{database}.sql
    2. Jar:classpath:/org/quartz/impl/jdbcjobstore/tables_{database}.sql
  • 想看源码的可以从org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration进

相关文章

网友评论

    本文标题:Quartz设计原理详解(多图)

    本文链接:https://www.haomeiwen.com/subject/kgsukqtx.html