quartz定时任务框架

概括

本文将介绍quartz的基本概念,简单使用,持久化,单机、集群配置等,方便各位同学快速了解quartz框架,并合理运用到项目中。

quartz简介

quartz是一个为java服务量身定制的定时任务框架,提供了持久化方案,集群解决方案,方便我们对一些简单场景的使用;对比其他定时任务方案,可以说是@Scheduled注解的升级版,但又不及xxl-job的强大

quartz 官网:https://www.quartz-scheduler.org/

quartz的四大组件

quartz总共有4个组件,基本上所有的操作都是围绕这几个组件来完成的

JobDetail

对Job任务的简单描述,可以设置job的名称,组,简单描述信息,携带的JobData数据,是否持久化等

  • name,group:组成jobKey(本服务job的唯一标识)
  • Description:job任务的简单描述
  • JobData:Map子类,主要用于传递数据,方便job代码中使用
  • storeDurable:是否持久化,当job不再被调用时,jobDetail信息继续存储在数据库中,不被删除
  • requestRecovery:是否恢复执行

Job

Job是一个接口,如果你定义一个任务类,就需要实现Job接口,并实现execute方法,job任务的业务代码放在execute方法中,被调用时可执行,方法参数中注入了JobExecutionContext对象,可以获取到jobDetail信息,JobData等内容

  • execute方法:任务业务代码执行方法,类似于Runable中的run方法
  • @DisallowConcurrentExecution:禁止并发执行,如果是两个job,那就是串型话
  • @PersistJobDataAfterExecution:执行后更新jobData中的数据,考虑并发数据问题,最好和@DisallowConcurrentExecution一起使用

Trigger

trigger是触发器,主要是用于定于触发时间,间隔,方案等

  • name和troup:trigger的唯一标识,同jobDetail
  • Description:trigger的简单描述
  • startAt:trigger工作开始时间,通过配置此项可设置在某个时间点后执行
  • endAt:trigger工作结束时间,通过配置此项可设置在某个时间点前执行
  • withSchedule:设置触发器频率实现方式,有四个实现方式

一般常用的是CronScheduleBuilder 和 SimpleScheduleBuilder两个

CronScheduleBuilder:通过设置cron表达式的方式来控制触发频率(如一秒执行一次 0/1 * * * * ?等)

SimpleScheduleBuilde:简单通过代码方式设置隔多久触发一次,例如每隔5秒

Schedule

这个和trigger中的ScheduleBuilder不同,这个Schedule是整个Quartz的调度器,用于控制任务的调度,在Schedule可以设置持久化,集群配置等

注意:Schedule在scheduleJob方法将JobDetail与Trigger关联之前,JobDetail和Trigger没有半毛钱关系。同时,因为JobDetail和Trigger等都有name和group,可以通过排列组合来完成不同的搭配,不过这种方案有点繁琐了,在需求不是很离谱的情况下,通常都是一个job配一个专门的trigger,舍弃那些排列组合,方便明了

SpringBoot整合Quartz

单机版

依赖

springboot选择2.2.1.RELEASE版本,其它跟随springboot的版本

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

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

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

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

编写一个job类用于执行业务代码

// 实际job执行类
@Log4j2
public class HelloJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //执行业务逻辑
        log.info("执行业务...");
    }
}

编写JobDetail和Trigger,并调用

@Component
public class QuartzService implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        // 项目初始化完成后执行,quartz业务

        // 调度器
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

        // job详情,描述job的执行类,job的名称,组等
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("jobName1", "group1")
                .build();

        // 触发器,描述触发器的名称、组,执行间隔等(有cron方式,也有简单的隔多久执行一次)
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("triggerName1", "group1")
                .startNow()
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(10))
                .build();

        // 在调度器上关联job和触发器
        scheduler.scheduleJob(jobDetail,trigger);

        // 启动调度器
        scheduler.start();
    }
}

很好,现在就完成了一个Quartz单机版和SpringBoot的整合项目,来看看执行效果,都是每10秒执行一次

以上只是简单单机版的做法,相比@Schedule也没强多少,却少持久化,集群重复执行问题

集群版

集群版解决了同一时间重复的问题,同时,集群依赖持久化,用的是mysql的锁来解决集群间调度的问题

对比单机版,需要额外添加mysql相关的依赖,并在对应的mysql库中创建quartz持久化相关的表

DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;

-- ----------------------------
-- 1、存储每一个已配置的 jobDetail 的详细信息
-- ----------------------------
create table QRTZ_JOB_DETAILS (
    sched_name           varchar(120)    not null            comment '调度名称',
    job_name             varchar(200)    not null            comment '任务名称',
    job_group            varchar(200)    not null            comment '任务组名',
    description          varchar(250)    null                comment '相关介绍',
    job_class_name       varchar(250)    not null            comment '执行任务类名称',
    is_durable           varchar(1)      not null            comment '是否持久化',
    is_nonconcurrent     varchar(1)      not null            comment '是否并发',
    is_update_data       varchar(1)      not null            comment '是否更新数据',
    requests_recovery    varchar(1)      not null            comment '是否接受恢复执行',
    job_data             blob            null                comment '存放持久化job对象',
    primary key (sched_name, job_name, job_group)
) engine=innodb comment = '任务详细信息表';

-- ----------------------------
-- 2、 存储已配置的 Trigger 的信息
-- ----------------------------
create table QRTZ_TRIGGERS (
    sched_name           varchar(120)    not null            comment '调度名称',
    trigger_name         varchar(200)    not null            comment '触发器的名字',
    trigger_group        varchar(200)    not null            comment '触发器所属组的名字',
    job_name             varchar(200)    not null            comment 'qrtz_job_details表job_name的外键',
    job_group            varchar(200)    not null            comment 'qrtz_job_details表job_group的外键',
    description          varchar(250)    null                comment '相关介绍',
    next_fire_time       bigint(13)      null                comment '上一次触发时间(毫秒)',
    prev_fire_time       bigint(13)      null                comment '下一次触发时间(默认为-1表示不触发)',
    priority             integer         null                comment '优先级',
    trigger_state        varchar(16)     not null            comment '触发器状态',
    trigger_type         varchar(8)      not null            comment '触发器的类型',
    start_time           bigint(13)      not null            comment '开始时间',
    end_time             bigint(13)      null                comment '结束时间',
    calendar_name        varchar(200)    null                comment '日程表名称',
    misfire_instr        smallint(2)     null                comment '补偿执行的策略',
    job_data             blob            null                comment '存放持久化job对象',
    primary key (sched_name, trigger_name, trigger_group),
    foreign key (sched_name, job_name, job_group) references QRTZ_JOB_DETAILS(sched_name, job_name, job_group)
) engine=innodb comment = '触发器详细信息表';

-- ----------------------------
-- 3、 存储简单的 Trigger,包括重复次数,间隔,以及已触发的次数
-- ----------------------------
create table QRTZ_SIMPLE_TRIGGERS (
    sched_name           varchar(120)    not null            comment '调度名称',
    trigger_name         varchar(200)    not null            comment 'qrtz_triggers表trigger_name的外键',
    trigger_group        varchar(200)    not null            comment 'qrtz_triggers表trigger_group的外键',
    repeat_count         bigint(7)       not null            comment '重复的次数统计',
    repeat_interval      bigint(12)      not null            comment '重复的间隔时间',
    times_triggered      bigint(10)      not null            comment '已经触发的次数',
    primary key (sched_name, trigger_name, trigger_group),
    foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group)
) engine=innodb comment = '简单触发器的信息表';

-- ----------------------------
-- 4、 存储 Cron Trigger,包括 Cron 表达式和时区信息
-- ---------------------------- 
create table QRTZ_CRON_TRIGGERS (
    sched_name           varchar(120)    not null            comment '调度名称',
    trigger_name         varchar(200)    not null            comment 'qrtz_triggers表trigger_name的外键',
    trigger_group        varchar(200)    not null            comment 'qrtz_triggers表trigger_group的外键',
    cron_expression      varchar(200)    not null            comment 'cron表达式',
    time_zone_id         varchar(80)                         comment '时区',
    primary key (sched_name, trigger_name, trigger_group),
    foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group)
) engine=innodb comment = 'Cron类型的触发器表';

-- ----------------------------
-- 5、 Trigger 作为 Blob 类型存储(用于 Quartz 用户用 JDBC 创建他们自己定制的 Trigger 类型,JobStore 并不知道如何存储实例的时候)
-- ---------------------------- 
create table QRTZ_BLOB_TRIGGERS (
    sched_name           varchar(120)    not null            comment '调度名称',
    trigger_name         varchar(200)    not null            comment 'qrtz_triggers表trigger_name的外键',
    trigger_group        varchar(200)    not null            comment 'qrtz_triggers表trigger_group的外键',
    blob_data            blob            null                comment '存放持久化Trigger对象',
    primary key (sched_name, trigger_name, trigger_group),
    foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group)
) engine=innodb comment = 'Blob类型的触发器表';

-- ----------------------------
-- 6、 以 Blob 类型存储存放日历信息, quartz可配置一个日历来指定一个时间范围
-- ---------------------------- 
create table QRTZ_CALENDARS (
    sched_name           varchar(120)    not null            comment '调度名称',
    calendar_name        varchar(200)    not null            comment '日历名称',
    calendar             blob            not null            comment '存放持久化calendar对象',
    primary key (sched_name, calendar_name)
) engine=innodb comment = '日历信息表';

-- ----------------------------
-- 7、 存储已暂停的 Trigger 组的信息
-- ---------------------------- 
create table QRTZ_PAUSED_TRIGGER_GRPS (
    sched_name           varchar(120)    not null            comment '调度名称',
    trigger_group        varchar(200)    not null            comment 'qrtz_triggers表trigger_group的外键',
    primary key (sched_name, trigger_group)
) engine=innodb comment = '暂停的触发器表';

-- ----------------------------
-- 8、 存储与已触发的 Trigger 相关的状态信息,以及相联 Job 的执行信息
-- ---------------------------- 
create table QRTZ_FIRED_TRIGGERS (
    sched_name           varchar(120)    not null            comment '调度名称',
    entry_id             varchar(95)     not null            comment '调度器实例id',
    trigger_name         varchar(200)    not null            comment 'qrtz_triggers表trigger_name的外键',
    trigger_group        varchar(200)    not null            comment 'qrtz_triggers表trigger_group的外键',
    instance_name        varchar(200)    not null            comment '调度器实例名',
    fired_time           bigint(13)      not null            comment '触发的时间',
    sched_time           bigint(13)      not null            comment '定时器制定的时间',
    priority             integer         not null            comment '优先级',
    state                varchar(16)     not null            comment '状态',
    job_name             varchar(200)    null                comment '任务名称',
    job_group            varchar(200)    null                comment '任务组名',
    is_nonconcurrent     varchar(1)      null                comment '是否并发',
    requests_recovery    varchar(1)      null                comment '是否接受恢复执行',
    primary key (sched_name, entry_id)
) engine=innodb comment = '已触发的触发器表';

-- ----------------------------
-- 9、 存储少量的有关 Scheduler 的状态信息,假如是用于集群中,可以看到其他的 Scheduler 实例
-- ---------------------------- 
create table QRTZ_SCHEDULER_STATE (
    sched_name           varchar(120)    not null            comment '调度名称',
    instance_name        varchar(200)    not null            comment '实例名称',
    last_checkin_time    bigint(13)      not null            comment '上次检查时间',
    checkin_interval     bigint(13)      not null            comment '检查间隔时间',
    primary key (sched_name, instance_name)
) engine=innodb comment = '调度器状态表';

-- ----------------------------
-- 10、 存储程序的悲观锁的信息(假如使用了悲观锁)
-- ---------------------------- 
create table QRTZ_LOCKS (
    sched_name           varchar(120)    not null            comment '调度名称',
    lock_name            varchar(40)     not null            comment '悲观锁名称',
    primary key (sched_name, lock_name)
) engine=innodb comment = '存储的悲观锁信息表';

-- ----------------------------
-- 11、 Quartz集群实现同步机制的行锁表
-- ---------------------------- 
create table QRTZ_SIMPROP_TRIGGERS (
    sched_name           varchar(120)    not null            comment '调度名称',
    trigger_name         varchar(200)    not null            comment 'qrtz_triggers表trigger_name的外键',
    trigger_group        varchar(200)    not null            comment 'qrtz_triggers表trigger_group的外键',
    str_prop_1           varchar(512)    null                comment 'String类型的trigger的第一个参数',
    str_prop_2           varchar(512)    null                comment 'String类型的trigger的第二个参数',
    str_prop_3           varchar(512)    null                comment 'String类型的trigger的第三个参数',
    int_prop_1           int             null                comment 'int类型的trigger的第一个参数',
    int_prop_2           int             null                comment 'int类型的trigger的第二个参数',
    long_prop_1          bigint          null                comment 'long类型的trigger的第一个参数',
    long_prop_2          bigint          null                comment 'long类型的trigger的第二个参数',
    dec_prop_1           numeric(13,4)   null                comment 'decimal类型的trigger的第一个参数',
    dec_prop_2           numeric(13,4)   null                comment 'decimal类型的trigger的第二个参数',
    bool_prop_1          varchar(1)      null                comment 'Boolean类型的trigger的第一个参数',
    bool_prop_2          varchar(1)      null                comment 'Boolean类型的trigger的第二个参数',
    primary key (sched_name, trigger_name, trigger_group),
    foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group)
) engine=innodb comment = '同步机制的行锁表';

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

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- JSON工具 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
        </dependency>

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

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- 实现对数据库连接池的自动化配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

mysql连接配置

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/quartz?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
    username: quartz
    password: quartz
    driver-class-name: com.mysql.cj.jdbc.Driver

Quartz的Schedule配置,可以用properties的配置文件方式,我这直接写代码中了

主要注意 

factory.setDataSource(dataSource);配置持久化数据源

prop.put("org.quartz.jobStore.isClustered", "true");配置集群模式

factory.setSchedulerName("cluster");设置服务名称,多服务时靠这个区分是哪个服务的标识

@Configuration
public class QuartzConfig {

    @Autowired
    private DataSource dataSource;

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() throws SchedulerException {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setDataSource(dataSource);

        // quartz参数
        Properties prop = new Properties();
        prop.put("org.quartz.scheduler.instanceName", "cluster");
        prop.put("org.quartz.scheduler.instanceId", "AUTO");
        // 线程池配置
        prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
        prop.put("org.quartz.threadPool.threadCount", "20");
        prop.put("org.quartz.threadPool.threadPriority", "5");
        // JobStore配置
        prop.put("org.quartz.jobStore.class", "org.springframework.scheduling.quartz.LocalDataSourceJobStore");
        // 集群配置
        prop.put("org.quartz.jobStore.isClustered", "true");
        prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
        prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "10");
        prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true");

        // sqlserver 启用
        // prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?");
        prop.put("org.quartz.jobStore.misfireThreshold", "12000");
        prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
        factory.setQuartzProperties(prop);

        factory.setSchedulerName("cluster");
        // 延时启动
        factory.setStartupDelay(1);
        factory.setApplicationContextSchedulerContextKey("applicationContextKey");
        // 可选,QuartzScheduler
        // 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
        factory.setOverwriteExistingJobs(true);
        // 设置自动启动,默认为true
        factory.setAutoStartup(true);

        return factory;
    }
}

job业务类

@Log4j2
@PersistJobDataAfterExecution   // 执行后更新jobData中的数据,考虑并发数据问题,最好和@DisallowConcurrentExecution一起使用
@DisallowConcurrentExecution    // 不允许并发执行
public class HelloJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // 业务逻辑
        JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
        String description = jobExecutionContext.getJobDetail().getDescription();
        log.info("hello ... data {}, description {}", JSON.toJSONString(jobDataMap),description);
    }
}

JobDetail和Trigger

注意,因为持久化的原因,项目在启动的时候会自动将数据库中的job初始化加载到服务中,如果代码中还是直接将创建job相关的代码写死的话,就会报JobKey已存在等问题,这时候就需要判断是否存在来创建job,单机本不用考虑此问题

@Log4j2
@Component
public class QuartzInitService implements CommandLineRunner {

    @Autowired
    private Scheduler scheduler;

    @Override
    public void run(String... args) throws Exception {
        // 完成初始化的job工作

        // 判断job是否存在,如果存在就不创建
        // 因为是采用数据库存储,在重启时不能重复创建job
        JobKey jobKey = JobKey.jobKey("job1", "group1");
        if(!scheduler.checkExists(jobKey)){
            //         job
            JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                    .withIdentity("job1", "group1")
                    .withDescription("测试job")
                    .usingJobData("1",2)
                    .requestRecovery()    // 设置是否恢复执行
                    .build();

            // trigger
            SimpleTrigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity("trigger1", "group1")
                    .startNow()
                    .withSchedule(
                            SimpleScheduleBuilder
//                                    .simpleSchedule()   // 如果只是这个,只会执行一次
                                    .repeatSecondlyForever(5)
                    )
                    .build();

            scheduler.scheduleJob(jobDetail,trigger);
        }
    }
}

这样就完成了Quartz集群化的搭建

quartz任务常见操作

cron表达式的任务

    @Test
    void addCronJob() throws SchedulerException {
        // cron 表达式job

        // 舍弃排列组合,以jobName的名称当成job、trigger的名称
        String jobName = "cronJob";

        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withDescription(jobName)
                .withIdentity(jobName,jobName)
                .usingJobData("name",jobName)
                .build();

//        jobDetail.isDurable()

        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(jobName,jobName)
                .withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?"))    // 每两秒执行一次
                .build();

        scheduler.scheduleJob(jobDetail,trigger);
    }

延时执行一次的任务

    @Test
    void addDelayJob() throws SchedulerException, ParseException {
        // 舍弃排列组合,以jobname的名称当成job、trigger的名称
        String jobName = "delayJob";
        
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity(jobName, jobName)
                .withDescription("延时job")
                .build();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        // 延时触发器实现方式
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(jobName, jobName)
                .startAt(DateBuilder.futureDate(20, DateBuilder.IntervalUnit.SECOND))   // 触发器开始工作时间,在此之前,都不会进行操作
                .withSchedule(SimpleScheduleBuilder.simpleSchedule())
                .build();

        // 可以通过设置startAt和endAt,配合.withSchedule等,设置定时任务在某个时间范围内才能执行
        scheduler.scheduleJob(jobDetail,trigger);
        // 延时任务完成后会自动删除,就算job设置持久化也会删除trigger
        log.info("delayJob commit ");
    }

执行固定次数的任务

    @Test
    void addRepeatCount() throws SchedulerException {
        // 创建一个指定次数的任务
        int count = 10;
        // 舍弃排列组合,以jobname的名称当成job、trigger的名称
        String jobName = "repeatCountJob";

        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity(jobName, jobName)
                .withDescription("延时job")
                .build();
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(jobName, jobName)
                .withSchedule(
                        SimpleScheduleBuilder.simpleSchedule()
                                .withIntervalInSeconds(2)   // 每2s执行一次
                                .withRepeatCount(count)     // 任务重复触发次数,设置10次,实际执行11次
                )
                .build();
        
        scheduler.scheduleJob(jobDetail,trigger);
    }

指定时间范围的任务

    @Test
    void addTimeScopeJob() throws SchedulerException {
        // 添加在一定时间范围的job
//      舍弃排列组合,以jobname的名称当成job、trigger的名称
        String jobName = "timeScopeJob";

        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity(jobName, jobName)
                .withDescription(jobName)
                .storeDurably()
                .build();
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(jobName, jobName)
                .withSchedule(
                        CronScheduleBuilder.cronSchedule("0/1 * * * * ?")
                )
                // 设置触发器运行的时间返回,以下内容为,接下来的第20-25秒这几秒秒时间范围内,会触发执行
                // 传入时间类型为Date,也可以通过其他格式设置时间范围,例如yyyy-MM-dd HH:mm:ss等
                .startAt(DateBuilder.futureDate(20, DateBuilder.IntervalUnit.SECOND))
                .endAt(DateBuilder.futureDate(25, DateBuilder.IntervalUnit.SECOND))
                .build();

        scheduler.scheduleJob(jobDetail,trigger);
        // 任务完成后会自动删除
    }

暂停任务

    @Test
    void pauseJobDetail() throws SchedulerException {
        // 暂停任务
        String jobName = "job1";
        String jobGroup = "group1";
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        scheduler.pauseJob(jobKey);
    }

恢复任务

    @Test
    void resumeJobDetail() throws SchedulerException {
        // 恢复任务
        String jobName = "cronJob";
        JobKey jobKey = JobKey.jobKey(jobName, jobName);
        scheduler.resumeJob(jobKey);
    }

删除任务

    @Test
    void deleteJob() throws SchedulerException {
        // 删除任务
        String jobName = "cronJob";
        JobKey jobKey = JobKey.jobKey(jobName, jobName);
        scheduler.deleteJob(jobKey);
    }

清除全部任务

    @Test
    void clearJob() throws SchedulerException {
        // 清除全部任务
        scheduler.clear();
    }

立即执行一次任务

    @Test
    void exeJobTest(){
        // 立即执行一次
        String name = "001";
        JobKey jobKey = JobKey.jobKey(name, name);
        scheduler.triggerJob(jobKey);
    }

总结

这几乎就是quartz定时任务常用的操作了,job的持久化,集群调度,控制并发执行,提供多种触发器,延时任务,时间范围控制等,对比简单的需求基本上就是足够了

总的来说,quartz入门简单,通过嵌入服务代码中,避免多使用其它机器来搭建job集群,适合少量服务的集群环境下使用

但是对比xxl-job,功能少(比如日志,调度方案,可视化界面等)不过xxl-job要自身搭建集群,需要额外的服务器资源

如果是服务众多,又需要面对各种复杂的环境,那么还是推荐使用XXL-JOB

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值