02. SpringBoot整合定时器Quartz

一 核心类说明

Scheduler:调度器。所有的调度都是由它控制,是Quartz的大脑,所有任务都是由它来管理

Job:任务,想定时执行的事情(定义业务逻辑)

JobDetail:基于Job,进一步包装。其中关联一个Job,并为Job指定更详细的属性,比如标识等

Trigger:触发器。可以指定给某个任务,指定任务的触发机制

二 简单使用

1. 导入依赖

	<dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
        <version>2.2.3</version>
    </dependency>

2. 实现Job接口,重写execute方法

/**
 * 工作类的具体实现,即到底要做什么事情
 */
public class HelloQuartz implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // 1. 创建工作详情
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        // 2. 获取工作的具体信息
        String jobName = jobDetail.getKey().getName();
        String jobGroup = jobDetail.getKey().getGroup();

        System.out.println("job执行,job:" + jobName + " group:" + jobGroup);
        System.out.println(new Date());
    }

    /**
     * 测试我们创建的job
     * @param args
     */
    public static void main(String[] args) {
        try {
            // 1. 创建一个默认的调度器
            Scheduler defaultScheduler = StdSchedulerFactory.getDefaultScheduler();
            // 2. 定义一个Trigger,用来触发执行job的条件
            // 使用TriggerBuilder触发构造器来构造Trigger
            TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
            Trigger trigger = triggerBuilder.withIdentity("trigger1", "group1")// 声明身份
                    .startNow() // 现在开启
                    .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1).repeatForever()) // 创建调度计划,每秒执行一次,一直重复
                    .endAt(new GregorianCalendar(2022, 7, 15, 16, 7, 0).getTime()) //2022年7月份结束
                    .build(); // 构建Trigger,前面的都是在填充条件
            // 3. 定义一个JobDetail,这个是关键!!!将HelloQuartz中定义的工作详情告诉JobDetail
            JobDetail job = JobBuilder.newJob(HelloQuartz.class).withIdentity("job1", "group1") //定义name/group
                    .build();
            // 4. 将job和触发器填充到调度器中
            defaultScheduler.scheduleJob(job, trigger);
            // 5. 启动任务调度
            defaultScheduler.start();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
}

三 Trigger触发器

1. SimpleTrigger 简单触发器

按照一定的时间间隔(单位是毫秒)执行的任务

  1. 指定开始和结束时间
  2. 指定时间间隔、执行次数

示例:

SimpleTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")
                .startNow()
            	.withSchedule(SimpleScheduleBuilder.simpleSchedule()
                          .withIntervalInSeconds(1) //每秒执行一次
                          .repeatForever())// 不限执行次数
                .endAt(new GregorianCalendar(2020, 4, 7, 2, 24, 0).getTime())
                .build();
SimpleTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")
                .startNow()
            	.withSchedule(SimpleScheduleBuilder.simpleSchedule()
                          .withIntervalInMinutes(3) // 每3分钟执行一次
                          .withRepeatCount(3)) // 执行次数不超过3次
                .endAt(new GregorianCalendar(2020, 4, 7, 2, 24, 0).getTime()) 
                .build();

2. CronTrigger 复杂触发器

适用于更加复杂的任务,支持类似于Linux Cron的语法

指定Cron表达式即可

示例:

// 每天10:00 - 12:00,每隔两分钟执行一次
CronTrigger cronTrigger = TriggerBuilder.newTrigger()
    		.withIndentity("t1", "g1")
    		.withSchedule(CronScheduleBuilder.cronSchedule("0 0/2 10-12 * * ?"))
    		.build();

1. Cron表达式组成

表达式组成:“秒 分 时 日 月 星期几 [年]” ,其中"年" 是可选的,一般不指定。

  • 如:"10 20 18 3 5 ?"代表"5月3日18点20分10秒,星期几不确定 "
位置时间域允许值特殊值
10-59, - * /
2分钟0-59, - * /
3小时0-23, - * /
4日期1-31, - * ? / L W
5月份1-12, - * /
6星期1-7, - * ? / L #
7年份(可选), - * /

2. Cron表达式符号

表达式中可使用的特殊符号的含义如下

符号语义
星号(*)可用在所有字段中,表示对应时间域的每一个时刻,例如, 在分钟字段时,表示“每分钟”
问号(?)该字符只在日期和星期字段中使用,它通常指定为“不确定值”
减号(-)表达一个范围,如在小时字段中使用“10-12”,则表示从10到12点,即10,11,12
逗号(,)表达一个列表值,如在星期字段中使用“MON,WED,FRI”,则表示星期一,星期三和星期五
斜杠(/)x/y表达一个等步长序列,x为起始值,y为增量步长值。如在分钟字段中使用0/15,则表示为0,15,30和45秒,而5/15在分钟字段 中表示5,20,35,50
井号(#)该字符只用在星期字段中,"4#2"代表第二个星期3,“5#4”代表第4个星期四
L该字符只在日期和星期字段中使用,代表“Last”的意思,但它在两个字段中意思不同。
如果L用在星期字段里,则表示星期六,等同于7
L出现在星期字段里,而且在前面有一个数值x,则表示“这个月的最后一个周x”,例如,6L表示该月的最后星期五
L在日期字段中,表示这个月份的最后一天,如一月的31号,非闰年二月的28号
W该字符只能出现在日期字段里,是对前导日期的修饰,表示离该日期最近的工作日
例如15W表示离该月15号最近的工作日,如果该月15号是星期六,则匹配14号星期五;如果15日是星期日,则匹配16号星期一;如果15号 是星期二,那结果就是15号星期二;但必须注意关联的匹配日期不能够跨月
LW组合在日期字段可以组合使用LW,它的意思是当月的最后一个工作日

3. Cron表达式示例

表示式说明
0 0 12 * * ?每天12点运行
0 15 10 * * ?每天10:15运行
0 15 10 * * ? 2008在2008年的每天10:15运行
0 * 14 * * ?每天14点到15点之间每分钟运行一次,开始于14:00,结束于14:59。
0 0/5 14 * * ?每天14点到15点每5分钟运行一次,开始于14:00,结束于14:55。
0 0/5 14,18 * * ?每天14点到15点每5分钟运行一次,此外每天18点到19点每5钟也运行一次。
0 0-5 14 * * ?每天14:00点到14:05,每分钟运行一次。
0 0-5/2 14 * * ?每天14:00点到14:05,每2分钟运行一次。
0 10,44 14 ? 3 43月每周三的14:10分和14:44分,各运行一次。
0 15 10 ? * 2-6每周一,二,三,四,五的10:15分运行一次。
0 15 10 15 * ?每月15日10:15分运行。
0 15 10 L * ?每月最后一天10:15分运行。
0 15 10 ? * 6L每月最后一个星期五10:15分运行。【此时天必须是"?"】
0 15 10 ? * 6L 2007-2009在2007,2008,2009年每个月的最后一个星期五的10:15分运行。

五 SpringBoot整合Quartz

1. 项目准备

创建用于存放任务相关信息的表

CREATE TABLE `task_config`  (
  `id` int UNSIGNED NOT NULL AUTO_INCREMENT,
  `task_id` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '任务id',
  `cron` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'cron表达式',
  `class_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'job引用地址',
  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '描述',
  `status` tinyint NOT NULL COMMENT '定时任务状态 0 停用,1启用',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

创建一个新的项目,添加依赖

<dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.18</version>
            <scope>provided</scope>
        </dependency>
        <!--quartz和springboot的整合包-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
            <version>2.0.4.RELEASE</version>
        </dependency>
        <!--mybatisPlus可以放我们更方便的操作mybatis-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.0</version>
        </dependency>
        <!--数据库连接池框架-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.9</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>


        <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-web</artifactId>
        </dependency>
    </dependencies>

配置文件

数据源的配置:application-datasource.yml配置文件

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=true&useSSL=false&allowMultiQueries=true&serverTimezone=UTC
    username: root
    password: ‘0000’
    type: com.alibaba.druid.pool.DruidDataSource

mybatisPlus的配置:application-mybatis.yml配置文件

mybatis-plus:
    #扫描xml的位置
  mapper-locations: classpath*:/dao/*.xml
  configuration:
    # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

Spring的配置:application.yml配置文件

spring:
  application:
    name: schedule-server
  profiles:
      #配置激活配置文件,application-mybatis,application-datasource
    active: datasource,mybatis
server:
  port: 9000

2. Entity、dao

库表对应的实体类

@Data
@Accessors(chain = true)
@TableName("task_config")
public class TaskConfigEntity implements Serializable {

    @TableId(value = "id",type = IdType.AUTO)
    private Integer id;

    @TableField("task_id")
    private String taskId;

    @TableField("cron")
    private String cron;

    @TableField("class_name")
    private String className;

    @TableField("description")
    private String description;

    @TableField("status")
    private Integer status;
}

dao层接口

@Mapper
public interface TaskConfigDao extends BaseMapper<TaskConfigEntity> {
}

对应的xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.example.demo.dao.TaskConfigDao">

</mapper>

在启动类上添加注解@MapperScan,这是Mybatis的注解,可以用来替代@Mapper

@SpringBootApplication
//扫描路径
@MapperScan("com.example.demo.dao")
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

3. 配置定时器Quartz

调度器Scheduler依赖调度器工厂SchedulerFactoryBean;调度器工厂SchedulerFactoryBean依赖线程池Executor和任务工厂JobFactory

1. 创建并配置线程池

@Configuration
public class ExecutorConfig {

    @Bean("taskExecutor")
    public Executor getAsyncExecutors() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(10);
        executor.setKeepAliveSeconds(5);
        // 队列容量
        executor.setQueueCapacity(0);
        // 拒绝策略
        executor.setRejectedExecutionHandler((Runnable r, ThreadPoolExecutor exec) -> {
            try {
                // offer():将指定的元素插入到队列中,必要的话(队列满了)进行等待一直到指定的超时时间
                if (!exec.getQueue().offer(r, 30, TimeUnit.SECONDS)) {
                    throw new Exception("任务等了30秒还没有进入队列中");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        });
        return executor;
    }
}

2.由于Quartz中底层的一个实例没有被Spring容器管理,所以我们需要创建这个示例并交给容器管理,这一步不可获缺!!!!

// Job工厂
@Component
public class JobFactory extends AdaptableJobFactory {
    /**
     * AutowireCapableBeanFactory接口是BeanFactory的子类,可以连接和填充那些生命周期不被Spring管理的已存在的bean实例
     */
    @Autowired
    private AutowireCapableBeanFactory capableBeanFactory;

    /**
     * 创建Job实例
     *
     * @param bundle
     * @return
     * @throws Exception
     */
    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        // 创建实例化对象
        Object jobInstance = super.createJobInstance(bundle);
        // 进行注入(使Spring管理该Bean),将jobInstance注入到Spring的ioc容器中
        capableBeanFactory.autowireBean(jobInstance);
        // 返回对象
        return jobInstance;
    }
}

3. 配置Scheduler调度器

@Configuration
public class ScheduleJobConfig {

    // 线程池
    @Resource(name = "taskExecutor")
    private Executor taskExecutor;

    /**
     * 调度器工厂实例
     * 通过JobFactory任务工厂创建一个调度器工厂
     *
     * @param jobFactory
     * @return
     */
    @Bean("schedulerFactory")
    public SchedulerFactoryBean createFactoryBean(JobFactory jobFactory) {
        // 1. new一个调度器工厂
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        // 2. 设置JobFactory任务工厂(这个spring没有自动帮我们创建,需要我们自己注册一个Bean,就是我们的上一步做的操作)
        schedulerFactoryBean.setJobFactory(jobFactory);
        // 3. 设置线程池
        schedulerFactoryBean.setTaskExecutor(taskExecutor);
        // 4. 设置overwriteExistJobs参数为true,可以通过使用外部文件的方式,修改已存活的job;否则修改将不会生效
        schedulerFactoryBean.setOverwriteExistingJobs(true);
        return schedulerFactoryBean;
    }

    /**
     * 调度器实例
     *
     * @param schedulerFactoryBean
     * @return
     */
    @Bean("scheduler1")
    public Scheduler getScheduler(@Qualifier("schedulerFactory") SchedulerFactoryBean schedulerFactoryBean) {
        return schedulerFactoryBean.getScheduler();
    }
}

4. 创建一个MyJob

public class MyJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println(jobExecutionContext.getJobDetail().getKey() + "===" + new SimpleDateFormat("hh:mm:ss").format(new Date()));
    }
}

4. 业务代码(Service层)

package com.example.demo.service;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.example.demo.dao.TaskConfigDao;
import com.example.demo.entity.TaskConfigEntity;
import lombok.extern.log4j.Log4j2;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
@Log4j2
public class ScheduleJobService {

    @Autowired
    private TaskConfigDao taskConfigDao;

    @Autowired
    private Scheduler scheduler;

    /**
     * 程序启动开始加载定时任务
     */
    public void startJob(){
        List<TaskConfigEntity> taskConfigEntities = taskConfigDao.selectList(
                Wrappers.<TaskConfigEntity>lambdaQuery()
                        .eq(TaskConfigEntity::getStatus, 1));
        if (taskConfigEntities == null || taskConfigEntities.size() == 0){
            log.error("定时任务加载数据为空");
            return;
        }
        for (TaskConfigEntity configEntity : taskConfigEntities) {
            CronTrigger cronTrigger = null;
            JobDetail jobDetail = null;
            try {
                cronTrigger = getCronTrigger(configEntity);
                jobDetail = getJobDetail(configEntity);
                scheduler.scheduleJob(jobDetail,cronTrigger);
                log.info("编号:{}定时任务加载成功",configEntity.getTaskId());
            }catch (Exception e){
                log.error("编号:{}定时任务加载失败",configEntity.getTaskId());
            }

        }
        try {
            scheduler.start();
        } catch (SchedulerException e) {
            log.error("定时任务启动失败",e);
        }
    }

    /**
     * 停止任务
     * @param taskId
     */
    public void stopJob(String taskId) throws SchedulerException {
        scheduler.pauseJob(JobKey.jobKey(taskId));
    }

    /**
     * 恢复任务
     * @param taskId
     * @throws SchedulerException
     */
    public void resumeJob(String taskId) throws SchedulerException {
        scheduler.resumeJob(JobKey.jobKey(taskId));
    }

    /**
     * 添加新的job
     * @param taskId
     * @throws SchedulerConfigException
     */
    public void loadJob(String taskId) throws SchedulerConfigException {
        TaskConfigEntity taskConfigEntity = taskConfigDao.selectOne(
                Wrappers.<TaskConfigEntity>lambdaQuery()
                        .eq(TaskConfigEntity::getTaskId, taskId)
                        .eq(TaskConfigEntity::getStatus, 1));
        if (taskConfigEntity == null){
            throw new SchedulerConfigException("未找到相关Job配置");
        }
        try {
            JobDetail jobDetail = getJobDetail(taskConfigEntity);
            CronTrigger cronTrigger = getCronTrigger(taskConfigEntity);
            scheduler.scheduleJob(jobDetail, cronTrigger);
        } catch (Exception e) {
            log.error("加载定时任务异常",e);
            throw new SchedulerConfigException("加载定时任务异常", e);
        }
    }
    public void unloadJob(String taskId) throws SchedulerException {
        // 停止触发器
        scheduler.pauseTrigger(TriggerKey.triggerKey(taskId));
        // 卸载定时任务
        scheduler.unscheduleJob(TriggerKey.triggerKey(taskId));
        // 删除原来的job
        scheduler.deleteJob(JobKey.jobKey(taskId));
    }

    /**
     * 重新加载执行计划
     * @throws Exception
     */
    public void reload(String taskId) throws Exception {
        TaskConfigEntity taskConfigEntity = taskConfigDao.selectOne(
                Wrappers.<TaskConfigEntity>lambdaQuery()
                        .eq(TaskConfigEntity::getTaskId, taskId)
                        .eq(TaskConfigEntity::getStatus, 1));

        String jobCode = taskConfigEntity.getTaskId();
        // 获取以前的触发器
        TriggerKey triggerKey = TriggerKey.triggerKey(jobCode);
        // 停止触发器
        scheduler.pauseTrigger(triggerKey);
        // 删除触发器
        scheduler.unscheduleJob(triggerKey);
        // 删除原来的job
        scheduler.deleteJob(JobKey.jobKey(jobCode));

        JobDetail jobDetail = getJobDetail(taskConfigEntity);
        CronTrigger cronTrigger = getCronTrigger(taskConfigEntity);
        // 重新加载job
        scheduler.scheduleJob(jobDetail, cronTrigger);
    }
    //组装JobDetail
    private JobDetail getJobDetail(TaskConfigEntity configEntity) throws ClassNotFoundException {

        Class<? extends Job> aClass = Class.forName(configEntity.getClassName()).asSubclass(Job.class);

        return JobBuilder.newJob()
                .withIdentity(JobKey.jobKey(configEntity.getTaskId()))
                .withDescription(configEntity.getDescription())
                .ofType(aClass).build();
    }
    //组装CronTrigger
    private CronTrigger getCronTrigger(TaskConfigEntity configEntity){
        CronTrigger cronTrigger = null;
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(configEntity.getCron());
        cronTrigger = TriggerBuilder.newTrigger()
                .withIdentity(TriggerKey.triggerKey(configEntity.getTaskId()))
                .withSchedule(cronScheduleBuilder)
                .build();
        return cronTrigger;
    }
}

5. 创建监听器,项目启动的时候开启定时任务

package com.example.demo.listener;

import com.example.demo.service.ScheduleJobService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

/**
 * 监听容器启动,并开始从数据库加载定时任务
 */
@Component
public class ScheduleJobInitListener implements CommandLineRunner {

    @Autowired
    private ScheduleJobService jobService;

    @Override
    public void run(String... strings) throws Exception {
        jobService.startJob();
    }
}

6. 通过远程请求加载定时任务

package com.example.demo.controller;

import com.example.demo.service.ScheduleJobService;
import org.quartz.SchedulerConfigException;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ScheduleJobController {
    @Autowired
    private ScheduleJobService jobService;

    @GetMapping("/load/{taskId}")
    public String loadJob(@PathVariable("taskId") String taskId){
        try {
            jobService.loadJob(taskId);
        } catch (SchedulerConfigException e) {
            return "导入定时任务失败";
        }
        return "成功";
    }
    @GetMapping("/resume/{taskId}")
    public String resumeJob(@PathVariable("taskId") String taskId){
        try {
            jobService.resumeJob(taskId);
        }catch (SchedulerException e) {
            return "恢复定时任务失败";
        }
        return "成功";
    }
    @GetMapping("/stop/{taskId}")
    public String stopJob(@PathVariable("taskId") String taskId){
        try {
            jobService.stopJob(taskId);
        }catch (SchedulerException e) {
            return "暂停定时任务失败";
        }
        return "成功";
    }
    @GetMapping("/unload/{taskId}")
    public String unloadJob(@PathVariable("taskId") String taskId){
        try {
            jobService.unloadJob(taskId);
        }catch (SchedulerException e) {
            return "卸载定时任务失败";
        }
        return "成功";
    }
}

7. 测试

在数据库中插入一条定时任务

INSERT INTO `test`.`task_config` (`id`, `task_id`, `cron`, `class_name`, `description`, `status`) VALUES ('1', 'TB00001', '0 * * * * ?', 'com.example.demo.job.MyJob', '每一分钟触发一次', '1');

然后启动框架,观察控制台

六 相关api和概念

1. 相关api及常用操作

调度器Scheduler

// 1. 向调度器中加载任务
Date scheduleJob(JobDetail var1, Trigger var2) throws SchedulerException;
// 2. 开启调度器
void start() throws SchedulerException;
// 3. 通过jobKey暂停某个Job
void pauseJob(JobKey var1) throws SchedulerException;
// 4. 恢复任务
void resumeJob(JobKey var1) throws SchedulerException;
// 5. 停止触发器
void pauseTrigger(TriggerKey var1) throws SchedulerException;
// 6. 卸载Job
boolean unscheduleJob(TriggerKey var1) throws SchedulerException;
// 7. 删除Job
boolean deleteJob(JobKey var1) throws SchedulerException;
  1. 删除Job的操作:
    1. 先停止触发器
    2. 再卸载Job
    3. 然后删除Job
  2. 如果Job中的配置发生了变化,需要先执行删除Job的操作,然后再执行加载Job的操作
  3. 当调度器开启之后,直接添加job之后会自动执行

2. 概念

  1. 调度器Scheduler是核心,使用的时候往里塞JobDetail和Trigger即可

  2. JobDetail和Trigger之间通过Jobkey相关联;实际上就是Jobkey中的name属性,可以是taskId

  3. JobDetail下的属性:jobKey、description、name、group、jobClass(Job任务)、jobDataMap(数据)、durablity(是否持久化)、shouldRecover(是否重写)

  4. 其中jobkey又有name和group

  5. CronTrigger中:TriggerKey和Schedule调度计划

创建方式

			// 创建触发器
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(task.getCron());
            CronTrigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(TriggerKey.triggerKey(task.getTaskId()))
                    .withSchedule(cronScheduleBuilder).build();

            // 创建job
            Class<? extends Job> taskConfigEntityJobClass = Class.forName(task.getClassName()).asSubclass(Job.class);
            JobDetail jobDetail = JobBuilder.newJob(taskConfigEntityJobClass)
                    .withIdentity(JobKey.jobKey(task.getTaskId()))
                    .withDescription(task.getDescription())
//                    .ofType(taskConfigEntityJobClass)
                    .build();

开启方式

// 加载到调度器中			
scheduler.scheduleJob(jobDetail, trigger);
// 开启
scheduler.start();

可参考:

  1. https://segmentfault.com/a/1190000039073805
  2. https://cloud.tencent.com/developer/article/1640190
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值