Springboot整合Quartz实现定时任务数据库动态配置

引入maven相关依赖

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

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

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

根据quartz官网下载源码,找到mysql innoDB的建表脚本

创建一个新的数据库,执行建表SQL

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;

CREATE TABLE QRTZ_JOB_DETAILS(
SCHED_NAME VARCHAR(120) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
JOB_CLASS_NAME VARCHAR(250) NOT NULL,
IS_DURABLE VARCHAR(1) NOT NULL,
IS_NONCONCURRENT VARCHAR(1) NOT NULL,
IS_UPDATE_DATA VARCHAR(1) NOT NULL,
REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))
ENGINE=InnoDB;

CREATE TABLE QRTZ_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
NEXT_FIRE_TIME BIGINT(13) NULL,
PREV_FIRE_TIME BIGINT(13) NULL,
PRIORITY INTEGER NULL,
TRIGGER_STATE VARCHAR(16) NOT NULL,
TRIGGER_TYPE VARCHAR(8) NOT NULL,
START_TIME BIGINT(13) NOT NULL,
END_TIME BIGINT(13) NULL,
CALENDAR_NAME VARCHAR(200) NULL,
MISFIRE_INSTR SMALLINT(2) NULL,
JOB_DATA BLOB NULL,
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;

CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
REPEAT_COUNT BIGINT(7) NOT NULL,
REPEAT_INTERVAL BIGINT(12) NOT NULL,
TIMES_TRIGGERED BIGINT(10) NOT NULL,
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;

CREATE TABLE QRTZ_CRON_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
CRON_EXPRESSION VARCHAR(120) NOT NULL,
TIME_ZONE_ID VARCHAR(80),
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;

CREATE TABLE QRTZ_SIMPROP_TRIGGERS
  (          
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    STR_PROP_1 VARCHAR(512) NULL,
    STR_PROP_2 VARCHAR(512) NULL,
    STR_PROP_3 VARCHAR(512) NULL,
    INT_PROP_1 INT NULL,
    INT_PROP_2 INT NULL,
    LONG_PROP_1 BIGINT NULL,
    LONG_PROP_2 BIGINT NULL,
    DEC_PROP_1 NUMERIC(13,4) NULL,
    DEC_PROP_2 NUMERIC(13,4) NULL,
    BOOL_PROP_1 VARCHAR(1) NULL,
    BOOL_PROP_2 VARCHAR(1) NULL,
    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;

CREATE TABLE QRTZ_BLOB_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
BLOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
INDEX (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;

CREATE TABLE QRTZ_CALENDARS (
SCHED_NAME VARCHAR(120) NOT NULL,
CALENDAR_NAME VARCHAR(200) NOT NULL,
CALENDAR BLOB NOT NULL,
PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))
ENGINE=InnoDB;

CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;

CREATE TABLE QRTZ_FIRED_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
ENTRY_ID VARCHAR(95) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
INSTANCE_NAME VARCHAR(200) NOT NULL,
FIRED_TIME BIGINT(13) NOT NULL,
SCHED_TIME BIGINT(13) NOT NULL,
PRIORITY INTEGER NOT NULL,
STATE VARCHAR(16) NOT NULL,
JOB_NAME VARCHAR(200) NULL,
JOB_GROUP VARCHAR(200) NULL,
IS_NONCONCURRENT VARCHAR(1) NULL,
REQUESTS_RECOVERY VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,ENTRY_ID))
ENGINE=InnoDB;

CREATE TABLE QRTZ_SCHEDULER_STATE (
SCHED_NAME VARCHAR(120) NOT NULL,
INSTANCE_NAME VARCHAR(200) NOT NULL,
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
CHECKIN_INTERVAL BIGINT(13) NOT NULL,
PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))
ENGINE=InnoDB;

CREATE TABLE QRTZ_LOCKS (
SCHED_NAME VARCHAR(120) NOT NULL,
LOCK_NAME VARCHAR(40) NOT NULL,
PRIMARY KEY (SCHED_NAME,LOCK_NAME))
ENGINE=InnoDB;

CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);

CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);
CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);

CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);

commit;

根据自身的项目建立一个自定义任务列表,用于前端展示以及创建新的任务、控制暂停、恢复定时任务等操作

DROP TABLE IF EXISTS `qrtz_task`;
CREATE TABLE `qrtz_task`  (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
  `job_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '任务名称',
  `job_group` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '任务所属组名称',
  `cron_expression` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'cron表达式',
  `job_class_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '任务执行时调用哪个类的方法(包名.类名:com.springboot.task.HelloJob)',
  `trigger_state` tinyint(1) NULL DEFAULT NULL COMMENT '任务状态(0:禁用/1:启用)',
  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '任务描述',
  `create_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人',
  `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
  `update_user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '修改人',
  `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间',
  `is_deleted` tinyint(1) NULL DEFAULT NULL COMMENT '是否删除(0:正常/1:已删除)',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '自定义定时任务列表' ROW_FORMAT = Dynamic;
在项目resources目录下自定义一个quartz.properties配置文件
#quartz集群配置
# ===========================================================================
# Configure Main Scheduler Properties 调度器属性
# ===========================================================================
#调度标识名 集群中每一个实例都必须使用相同的名称
org.quartz.scheduler.instanceName=DefaultQuartzScheduler
#ID设置为自动获取 每一个必须不同
org.quartz.scheduler.instanceid=AUTO
#============================================================================
# Configure ThreadPool
#============================================================================
#线程池的实现类(一般使用SimpleThreadPool即可满足几乎所有用户的需求)
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
#指定线程数,至少为1(无默认值)(一般设置为1-100直接的整数合适)
org.quartz.threadPool.threadCount=50
#设置线程的优先级(最大为java.lang.Thread.MAX_PRIORITY 10,最小为Thread.MIN_PRIORITY 1,默认为5)
org.quartz.threadPool.threadPriority=5
#============================================================================
# Configure JobStore
#============================================================================
# 信息保存时间 默认值60秒
org.quartz.jobStore.misfireThreshold=60000
#数据保存方式为数据库持久化
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
#数据库代理类,一般org.quartz.impl.jdbcjobstore.StdJDBCDelegate可以满足大部分数据库
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#JobDataMaps是否都为String类型
org.quartz.jobStore.useProperties=false
#数据库别名 随便取
org.quartz.jobStore.dataSource=myDS
#表的前缀,默认QRTZ_
org.quartz.jobStore.tablePrefix=QRTZ_
#是否加入集群
org.quartz.jobStore.isClustered=true
#调度实例失效的检查时间间隔
org.quartz.jobStore.clusterCheckinInterval=20000
项目当中的yml配置,使用的是spring-cloud-alibaba-nacos注册中心加dubbo
server:
  port: 8085
spring:
  application:
    name: dubbo-task
  cloud:
    nacos:
      discovery:
        # nacos集群方式就是把所有数据持久化到mysql数据库
        # 多个注册中心配置ip1:port1,ip2:port2,ip3:port3
        server-addr: 192.168.3.192:8848
  main:
    allow-bean-definition-overriding: true
  datasource:
    # Mysql配置
    # com.mysql.jdbc.Driver是mysql-connector-java 5版本的驱动名称,5版本之后替换为com.mysql.cj.jdbc.Driver
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/dubbo_task?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT&tinyInt1isBit=false
    username: root
    password: 123456
    #schema-username: root
    #schema-password: 123456
    #schema: classpath:quartz_tables.sql
    #initialization-mode: always
# 如果没有调用其他微服务的操作,无需dubbo相关配置
dubbo:
  protocol:
    name: dubbo
    port: -1
  registry:
    address: spring-cloud://192.168.3.192
  cloud:
    # 订阅服务提供者, 要订阅多个服务,请使用,(英文逗号)作为分隔符
    subscribed-services: dubbo-provider
    # 解决Dubbo中生产者未启动, 使用@Reference实例化的对象都是null
    # 消费者启动报错的问题, 很多时候服务是提供者也是消费者
    # 启动时检查提供者是否存在,true报错,false忽略  默认值true
    check: false
    # 远程服务调用超时时间(毫秒), 默认值1000
    timeout: 20000

mybatis-plus:
  # MyBatis 配置文件位置,如果有单独的 MyBatis 配置,请将其路径配置到 configLocation 中
  configLocation:
  # MyBatis Mapper 所对应的 XML 文件位置
  mapperLocations: classpath:/mapper/**/*.xml
  configuration:
    # 是否开启自动驼峰命名规则(camel case)映射
    # 即从经典数据库列名 A_COLUMN(下划线命名) 到经典 Java 属性名 aColumn(驼峰命名) 的类似映射
    # 如果数据库命名符合规则无需使用 @TableField 注解指定数据库字段名
    mapUnderscoreToCamelCase: true
    # 是否开启Mybatis二级缓存,默认为 true
    cacheEnabled: false
  global-config:
    db-config:
      # 表名是否使用驼峰转下划线命名,只对表名生效,默认 true
      tableUnderline: true
      logicDeleteField: isDeleted  # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logicDeleteValue: 1 # 逻辑已删除值(默认为 1)
      logicNotDeleteValue: 0 # 逻辑未删除值(默认为 0)
创建一个JobFactory类,用于将JobFactory注入到spring里
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;

/**
 * @author Administrator
 * @description Job的创建是由Quartz通过反射创建的
 * 并未交由Spring容器创建。故原则上来说,是无法在Job实例中使用依赖注入
 * @date 2021-03-12 16:29
 */
@Component
public class JobFactory extends AdaptableJobFactory {

    @Autowired
    private AutowireCapableBeanFactory capableBeanFactory;

    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        Object jobInstance = super.createJobInstance(bundle);
        // 使用AutowireCapableBeanFactory完成对IOC外Bean的注入操作
        capableBeanFactory.autowireBean(jobInstance);
        return jobInstance;
    }



}

创建一个QuartzConfig类,用于注入Scheduler相关的Bean

import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

import javax.sql.DataSource;
import java.io.IOException;
import java.util.Properties;

/**
 * @author Administrator
 * @description
 * @date 2021-03-12 16:27
 */
@Configuration
public class QuartzConfig {

    @Autowired
    private JobFactory jobFactory;
    @Autowired
    private DataSource dataSource;

    @Bean(name = "schedulerFactory")
    public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        schedulerFactoryBean.setQuartzProperties(quartzProperties());
        schedulerFactoryBean.setJobFactory(jobFactory);
        schedulerFactoryBean.setOverwriteExistingJobs(true);
        // 设置自行启动
        schedulerFactoryBean.setAutoStartup(true);
        // 延时启动
        schedulerFactoryBean.setStartupDelay(1);
        // 使用yml文件配置中的dataSource
        schedulerFactoryBean.setDataSource(dataSource);
        return schedulerFactoryBean;
    }

    @Bean(name = "scheduler")
    public Scheduler scheduler() throws IOException {
        return schedulerFactoryBean().getScheduler();
    }

    @Bean
    public Properties quartzProperties() throws IOException {
        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
        propertiesFactoryBean.setLocation(new ClassPathResource("quartz.properties"));
        propertiesFactoryBean.afterPropertiesSet();
        return propertiesFactoryBean.getObject();
    }

}

定义一个恢复任务、暂停任务使用的枚举类,该类可有可无,看自身需求,主要用于前端页面操作暂停、启用定时任务时,后台判断状态字段的值

/**
 * @author Administrator
 * @description
 * @date 2021-03-12 18:02
 */
public enum TaskStatusEnum {

    NORMAL(1, "正常"),
    PAUSED(0, "暂停");
    private int code;
    private String name;

    TaskStatusEnum(int code, String name) {
        this.code = code;
        this.name = name;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getName() {
        return name;
    }

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

创建一个包含新增、暂停、恢复、删除、修改cron表达式、用于操作定时任务的类

import com.springcloud.dubbo_task.dto.TaskDTO;
import com.springcloud.dubbo_task.common.TaskStatusEnum;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * @author Administrator
 * @description
 * @date 2021-03-16 14:36
 */
@Component
public class QuartzJobManager {

    private static final Logger logger = LoggerFactory.getLogger(QuartzJobManager.class);

    @Autowired
    private Scheduler scheduler;

    /**
     * 根据参数配置创建新的定时任务
     * @param task
     */
    @SuppressWarnings("unchecked")
    public void addJob(TaskDTO task) {
        try {
            // 创建jobDetail实例,绑定Job实现类
            // 指明job的名称,所在组的名称,以及绑定job类
            Class<? extends Job> jobClass = (Class<? extends Job>) (Class.forName(task.getBeanClass()).newInstance()
                    .getClass());
            addJob(task.getJobName(), task.getJobGroup(), task.getCronExpression(),jobClass);
            // 是否启用任务, 默认启用
            if (task.getJobStatus() == TaskStatusEnum.NORMAL.getCode()) {
                pauseJob(task.getJobName(), task.getJobGroup());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 创建一个新的定时任务
     * @param jobName 任务名称
     * @param jobGroup 任务所属组名
     * @param cronExpression cron表达式
     * @param clazz 任务类
     */
    public void addJob(String jobName, String jobGroup, String cronExpression, Class clazz) {
        addJob(jobName, jobGroup, cronExpression, clazz, null);

    }

    /**
     * 创建一个新的定时任务,可传参
     * @param jobName
     * @param jobGroup
     * @param cronExpression
     * @param clazz
     * @param map
     */
    public void addJob(String jobName, String jobGroup, String cronExpression, Class clazz,
                       Map<String, Object> map) {
        try {
            JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(jobName, jobGroup).build();
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup).withSchedule(scheduleBuilder).build();
            if (map != null) {
                trigger.getJobDataMap().putAll(map);
            }
            scheduler.scheduleJob(jobDetail, trigger);
            if (scheduler.isShutdown()) {
                scheduler.start();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 更新定时任务的频率
     * @param jobName
     * @param jobGroup
     * @param cronExpression
     */
    public void updateJob(String jobName, String jobGroup, String cronExpression) {
        updateJob(jobName, jobGroup, cronExpression, null);
    }

    /**
     * 更新频率和参数
     * @param jobName
     * @param jobGroup
     * @param cronExpression
     * @param map
     */
    public void updateJob(String jobName, String jobGroup, String cronExpression, Map<String, Object> map) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
            // 表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            // 按新的cronExpression表达式重新构建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
            //修改map
            if (map != null) {
                trigger.getJobDataMap().putAll(map);
            }
            // 按新的trigger重新设置job执行
            scheduler.rescheduleJob(triggerKey, trigger);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 只更新参数
     * @param jobName
     * @param jobGroup
     * @param map
     */
    public void updateJob(String jobName, String jobGroup, Map<String, Object> map) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            //修改map
            trigger.getJobDataMap().putAll(map);
            // 按新的trigger重新设置job执行
            scheduler.rescheduleJob(triggerKey, trigger);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 暂停指定任务
     * @param jobName
     * @param jobGroup
     */
    public void pauseJob(String jobName, String jobGroup) {
        try {
            scheduler.pauseJob(JobKey.jobKey(jobName, jobGroup));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 恢复任务
     * @param jobName
     * @param jobGroup
     */
    public void resumeJob(String jobName, String jobGroup) {
        try {
            scheduler.resumeJob(JobKey.jobKey(jobName, jobGroup));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 删除任务
     * @param jobName
     * @param jobGroup
     */
    public void deleteJob(String jobName, String jobGroup) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
            scheduler.pauseTrigger(triggerKey);
            scheduler.unscheduleJob(triggerKey);
            scheduler.deleteJob(JobKey.jobKey(jobName, jobGroup));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 启动所有任务
     */
    public void startJobs() {
        try {
            scheduler.start();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 关闭所有定时任务
     */
    public void shutdownJobs() {
        try {
            if (!scheduler.isShutdown()) {
                scheduler.shutdown();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取所有定时任务列表
     * @return
     */
    public List<Map<String, Object>> getAllJob() {
        GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
        List<Map<String, Object>> jobList = new ArrayList<>();
        Set<JobKey> jobKeys = null;
        try {
            jobKeys = scheduler.getJobKeys(matcher);
            for (JobKey jobKey : jobKeys) {
                List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
                for (Trigger trigger : triggers) {
                    Map<String, Object> job = new HashMap<>();
                    job.put("jobName", jobKey.getName());
                    job.put("jobGroup", jobKey.getGroup());
                    job.put("trigger", trigger.getKey());
                    Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
                    job.put("triggerState", triggerState.name());
                    if (trigger instanceof CronTrigger) {
                        CronTrigger cronTrigger = (CronTrigger) trigger;
                        String cronExpression = cronTrigger.getCronExpression();
                        job.put("cronExpression", cronExpression);
                    }
                    jobList.add(job);
                }
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return jobList;
    }
}

根据自身需求创建一个用于前端调用后台接口传参的TaskDTO,对应自定义的任务列表字段

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * @author Administrator
 * @description
 * @date 2021-03-16 16:11
 */
@Data
public class TaskDTO implements Serializable {

    private static final long serialVersionUID = -2804443468276676760L;

    /**
     * 主键
     */
    private int id;
    /**
     * 任务名
     */
    private String jobName;
    /**
     * 任务组名
     */
    private String jobGroup;
    /**
     * cron表达式
     */
    private String cronExpression;
    /**
     * 格式:包名.类名
     * com.springcloud.dubbo_task.task.HelloJob
     */
    private String jobClassName;
    /**
     * 任务状态(0:禁用/1:启用)
     */
    private int triggerState= 1;
    /**
     * 任务描述
     */
    private String description;
}

创建一个用来执行指定的定时任务的类

import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;

/**
 * @author Administrator
 * @description @DisallowConcurrentExecution : 该注解用在实现Job的类上面,意思是不允许并发执行
 * 注org.quartz.threadPool.threadCount的数量有多个的情况,@DisallowConcurrentExecution才生效
 * @date 2021-03-15 18:04
 */
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class HelloJob implements Job {

    private static final Logger logger = LoggerFactory.getLogger(HelloJob.class);

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        logger.info("----------HelloJob定时任务执行逻辑----------");
        System.out.println("==========定时任务执行==========" + new Date());
        // 可以调用其他微服务的接口进行业务逻辑处理
    }
}

前端调用接口,动态操作定时任务

import com.springcloud.dubbo_api.service.HelloServiceApi;
import com.springcloud.dubbo_task.dto.TaskDTO;
import com.springcloud.dubbo_task.service.TaskService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * @author Administrator
 * @description
 * @date 2021-03-16 18:03
 */
@RestController
@RequestMapping(value = "/job")
public class TaskController {

    @Autowired
    private TaskService taskService;
    @Reference
    private HelloServiceApi helloServiceApi;

    @GetMapping(value = "hello")
    public void hello() {
        String name = helloServiceApi.hello("task");
        System.out.println("====调用服务返回值====" + name);
    }

    /**
     * 添加一个新的任务
     * @param task
     */
    @PostMapping(value = "add")
    public void add(@RequestBody TaskDTO task) {
        taskService.add(task);
    }

    /**
     * 变更任务的执行频率
     * @param task
     */
    @PutMapping(value = "updateCron")
    public void updateCron(@RequestBody TaskDTO task) {
        taskService.updateCron(task);
    }

    /**
     * 暂停/恢复任务
     * @param task
     */
    @PutMapping(value = "updateStatus")
    public void updateStatus(@RequestBody TaskDTO task) {
        taskService.updateStatus(task);
    }

    /**
     * 删除任务
     * @param task
     */
    @DeleteMapping(value = "deleteJob")
    public void deleteJob(@RequestBody TaskDTO task) {
        taskService.deleteJob(task);
    }
}

TaskService

import com.springcloud.dubbo_task.dto.TaskDTO;

/**
 * @author Administrator
 * @description
 * @date 2021-03-16 17:25
 */
public interface TaskService {

    void add(TaskDTO task);

    void updateCron(TaskDTO task);

    void updateStatus(TaskDTO task);

    void deleteJob(TaskDTO task);

    void initSchedule();
}

业务逻辑实现类TaskServiceImpl

import com.springcloud.dubbo_task.dto.TaskDTO;
import com.springcloud.dubbo_task.common.TaskStatusEnum;
import com.springcloud.dubbo_task.entity.QrtzTaskEntity;
import com.springcloud.dubbo_task.manage.QuartzJobManager;
import com.springcloud.dubbo_task.mapper.TaskMapper;
import com.springcloud.dubbo_task.service.TaskService;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.InvocationTargetException;
import java.util.Date;
import java.util.List;

/**
 * @author Administrator
 * @description
 * @date 2021-03-16 17:26
 */
@Service
public class TaskServiceImpl implements TaskService {

    @Autowired
    private TaskMapper taskMapper;
    @Autowired
    private QuartzJobManager quartzJobManager;

    @Override
    public void add(TaskDTO task) {
        try {
            QrtzTaskEntity taskEntity = new QrtzTaskEntity();
            BeanUtils.copyProperties(taskEntity, task);
            taskEntity.setCreateUser("张三");
            taskEntity.setCreateTime(new Date());
            taskEntity.setIsDeleted(0);
            int result = taskMapper.insertJob(taskEntity);
            if (result > 0) {
                quartzJobManager.addJob(task);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void updateCron(TaskDTO task) {
        QrtzTaskEntity taskEntity = new QrtzTaskEntity();
        try {
            BeanUtils.copyProperties(taskEntity, task);
            taskEntity.setUpdateUser("李四");
            taskEntity.setUpdateTime(new Date());
            taskMapper.updateCron(taskEntity);
            quartzJobManager.updateJob(task.getJobName(), task.getJobGroupName(), task.getCronExpression());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void updateStatus(TaskDTO task) {
        QrtzTaskEntity taskEntity = new QrtzTaskEntity();
        try {
            BeanUtils.copyProperties(taskEntity, task);
            taskEntity.setUpdateUser("李四");
            taskEntity.setUpdateTime(new Date());
            taskMapper.updateStatus(taskEntity);
            if (task.getJobStatus() == TaskStatusEnum.NORMAL.getCode()) {
                quartzJobManager.resumeJob(task.getJobName(), task.getJobGroup());
            } else {
                quartzJobManager.pauseJob(task.getJobName(), task.getJobGroup());
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void deleteJob(TaskDTO task) {
        QrtzTaskEntity taskEntity = new QrtzTaskEntity();
        try {
            BeanUtils.copyProperties(taskEntity, task);
            taskEntity.setUpdateUser("李四");
            taskEntity.setUpdateTime(new Date());
            taskEntity.setIsDeleted(1);
            taskMapper.deleteJob(taskEntity);
            quartzJobManager.deleteJob(task.getJobName(), task.getJobGroup());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void initSchedule() {
        List<TaskDTO> list = taskMapper.listTasks();
        for(TaskDTO task : list) {
            if (task.getJobStatus() == TaskStatusEnum.NORMAL.getCode()) {
                quartzJobManager.resumeJob(task.getJobName(), task.getJobGroup());
            }
        }
    }
}

TaskMapper.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.springcloud.dubbo_task.mapper.TaskMapper">

    <select id="listTasks" resultType="com.springcloud.dubbo_task.dto.TaskDTO">
        select * from qrtz_task
    </select>

    <insert id="insertJob">
        insert into qrtz_task
          (
          job_name,job_group,cron_expression,job_class_name,trigger_state,description,
          create_user,create_time,is_deleted
          )
          values
          (
          #{jobName},#{jobGroupName},#{cronExpression},#{jobClassName},#{triggerState},#{description},
          #{createUser},#{createTime},#{isDeleted}
          )
    </insert>

    <select id="findJobById" resultType="com.springcloud.dubbo_task.entity.QrtzTaskEntity">
        select * from qrtz_task where id = #{id}
    </select>

    <update id="updateCron">
        update qrtz_task
        <set>
            <if test="jobName != null and jobName != ''">
                job_name = #{jobName},
            </if>
            <if test="jobGroup != null and jobGroup != ''">
                job_group = #{jobGroup},
            </if>
            <if test="cronExpression != null and cronExpression != ''">
                cron_expression = #{cronExpression},
            </if>
            <if test="jobClassName!= null and jobClassName != ''">
                job_class_name= #{jobClassName},
            </if>
            <if test="triggerState != null">
                trigger_state= #{triggerState},
            </if>
            <if test="updateUser != null and updateUser != ''">
                update_user = #{updateUser},
            </if>
            <if test="updateTime != null">
                update_time = #{updateTime},
            </if>
        </set>
        where id = #{id}
    </update>

    <update id="updateStatus">
        update qrtz_task
        <set>
            <if test="triggerState != null">
                trigger_state= #{triggerState},
            </if>
            <if test="updateUser != null and updateUser != ''">
                update_user = #{updateUser},
            </if>
            <if test="updateTime != null">
                update_time = #{updateTime},
            </if>
        </set>
        where id = #{id}
    </update>

    <update id="deleteJob">
        update qrtz_task
        <set>
            <if test="isDeleted != null">
                is_deleted = #{isDeleted},
            </if>
            <if test="updateUser != null and updateUser != ''">
                update_user = #{updateUser},
            </if>
            <if test="updateTime != null">
                update_time = #{updateTime},
            </if>
        </set>
        where id = #{id}
    </update>

</mapper>

整体pom.xml文件依赖配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.springcloud</groupId>
    <artifactId>dubbo_task</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>dubbo_task</name>
    <description>dubbo_task project for Spring Boot</description>

    <!--自定义属性值 一般自定义依赖包的版本号与指定项目字符编码-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR3</spring-cloud.version>
        <spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
        <mybatis-plus.version>3.3.0</mybatis-plus.version>
        <swagger.version>2.9.2</swagger.version>
    </properties>

    <dependencies>
        
        <!--引入微服务的api依赖-->
        <dependency>
            <groupId>com.springcloud</groupId>
            <artifactId>dubbo_api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

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

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

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

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-dubbo</artifactId>
        </dependency>
        <!--nacos注册中心-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--引入JDBC-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!--引入mysql驱动包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--Api接口文档生成工具 swagger2需与swagger-ui搭配使用-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>${swagger.version}</version>
        </dependency>
        <!--swagger-ui界面-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>${swagger.version}</version>
        </dependency>
        <!--字符串处理与校验的工具包-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.9</version>
        </dependency>
        <!--Apache开源组织提供的用于操作java bean的工具包-->
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.9.4</version>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

涉及到微服务之间调用的定时任务

package com.springcloud.dubbo_task.task;

import com.springcloud.dubbo_api.service.HelloServiceApi;
import org.apache.dubbo.config.annotation.Reference;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.util.Date;

/**
 * @author Administrator
 * @description 
 * @date 2021-03-17 14:11
 */
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
//@Component  注意:无需加@Component注解,当前服务启动,而调用的微服务未启动时,会造成当前服务启动失败
public class ProviderTask implements Job {

    @Reference
    private HelloServiceApi helloServiceApi;

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("==========调用另一个服务的接口执行业务处理==========" + new Date());
        try {
            helloServiceApi.hello("dubbo_task");
        } catch (Exception e) {
            JobExecutionException ex = new JobExecutionException(e);
            // true 表示立即重新执行该任务, 不断重试,直到成功,项目中不能确定其他服务中断的时间有多长,不建议设置该参数
            // 微服务中,比如当前为A服务,调用B服务的接口,而B服务中断重启,当B服务重启成功并且调用接口成功后退出该异常循环,类似心跳机制
            //ex.setRefireImmediately(true);
            // true 表示 Quartz 会自动取消所有与这个 job 有关的 trigger,从而避免再次运行 job
            // 当定时任务较多时,出现异常可记录该任务的信息到数据库,使用另一个定时任务不断扫描是否有异常的任务,进行恢复
            // 根据业务需求,如果定时任务执行间隔较长,建议手动恢复
            ex.setUnscheduleAllTriggers(true);
            throw ex;
        }
    }
}

spring-cloud-alibaba + dubbo + nacos注册中心 + quartz定时任务微服务之间调用的demo资源已上传

https://download.csdn.net/download/m0_37845840/15871428

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
好的,以下是 SpringBoot 搭配 Quartz 实现动态定时任务的源码: 1. 首先,我们需要引入 QuartzSpringBoot 的依赖: ```xml <!-- Quartz相关依赖 --> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.3.2</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz-jobs</artifactId> <version>2.3.2</version> </dependency> <!-- SpringBoot相关依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> ``` 2. 创建定时任务实体类,用于封装定时任务的信息,包括任务名称、任务组、任务类名、任务状态(是否启用)、任务表达式等: ```java @Entity @Table(name = "job_task") @Data public class JobTask implements Serializable { private static final long serialVersionUID = 1L; /** * ID */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; /** * 任务名称 */ @NotBlank(message = "任务名称不能为空") private String name; /** * 任务分组 */ @NotBlank(message = "任务分组不能为空") private String group; /** * 任务类名 */ @NotBlank(message = "任务类名不能为空") private String className; /** * 任务状态,0:禁用,1:启用 */ @NotNull(message = "任务状态不能为空") private Integer status; /** * 任务表达式 */ @NotBlank(message = "任务表达式不能为空") private String cronExpression; /** * 创建时间 */ private LocalDateTime createTime; /** * 最后一次修改时间 */ private LocalDateTime updateTime; } ``` 3. 创建定时任务的服务类,用于管理定时任务的增删改查等操作,同时也需要实现 `InitializingBean` 接口,在启动应用时加载已存在的定时任务: ```java @Service @AllArgsConstructor public class JobTaskService implements InitializingBean { private final Scheduler scheduler; private final JobTaskRepository jobTaskRepository; /** * 添加任务 * @param jobTask * @return * @throws Exception */ public boolean addJobTask(JobTask jobTask) throws Exception { if (jobTask == null || StringUtils.isBlank(jobTask.getCronExpression())) { return false; } if (StringUtils.isBlank(jobTask.getName()) || StringUtils.isBlank(jobTask.getClassName())) { throw new Exception("任务名称或任务类名不能为空"); } // 判断任务是否已存在 JobKey jobKey = JobKey.jobKey(jobTask.getName(), jobTask.getGroup()); if (scheduler.checkExists(jobKey)) { return false; } // 构建任务实例 JobDetail jobDetail = JobBuilder.newJob(getClass(jobTask.getClassName()).getClass()) .withIdentity(jobTask.getName(), jobTask.getGroup()) .build(); // 构建任务触发器 CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(jobTask.getCronExpression()); CronTrigger trigger = TriggerBuilder.newTrigger() .withIdentity(jobTask.getName(), jobTask.getGroup()) .withSchedule(cronScheduleBuilder) .build(); // 注册任务和触发器 scheduler.scheduleJob(jobDetail, trigger); // 如果任务状态为启用,则立即启动任务 if (jobTask.getStatus() == 1) { scheduler.triggerJob(jobKey); } // 保存任务信息 jobTask.setCreateTime(LocalDateTime.now()); jobTask.setUpdateTime(LocalDateTime.now()); jobTaskRepository.save(jobTask); return true; } /** * 修改任务 * @param jobTask * @return * @throws Exception */ public boolean modifyJobTask(JobTask jobTask) throws Exception { if (jobTask == null || StringUtils.isBlank(jobTask.getCronExpression())) { return false; } if (StringUtils.isBlank(jobTask.getName()) || StringUtils.isBlank(jobTask.getClassName())) { throw new Exception("任务名称或任务类名不能为空"); } // 判断任务是否存在 JobKey jobKey = JobKey.jobKey(jobTask.getName(), jobTask.getGroup()); if (!scheduler.checkExists(jobKey)) { return false; } // 修改任务触发器 CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(jobTask.getCronExpression()); CronTrigger newTrigger = TriggerBuilder.newTrigger() .withIdentity(jobTask.getName(), jobTask.getGroup()) .withSchedule(cronScheduleBuilder) .build(); scheduler.rescheduleJob(TriggerKey.triggerKey(jobTask.getName(), jobTask.getGroup()), newTrigger); // 修改任务信息 JobTask oldJobTask = jobTaskRepository.findByNameAndGroup(jobTask.getName(), jobTask.getGroup()); oldJobTask.setClassName(jobTask.getClassName()); oldJobTask.setStatus(jobTask.getStatus()); oldJobTask.setCronExpression(jobTask.getCronExpression()); oldJobTask.setUpdateTime(LocalDateTime.now()); jobTaskRepository.save(oldJobTask); return true; } /** * 删除任务 * @param name * @param group * @return * @throws Exception */ public boolean deleteJobTask(String name, String group) throws Exception { JobKey jobKey = JobKey.jobKey(name, group); if (!scheduler.checkExists(jobKey)) { return false; } scheduler.deleteJob(jobKey); jobTaskRepository.deleteByNameAndGroup(name, group); return true; } /** * 获取所有任务 * @return */ public List<JobTask> getAllJobTask() { return jobTaskRepository.findAll(); } /** * 根据任务名称和分组获取任务信息 * @param name * @param group * @return */ public JobTask getJobTaskByNameAndGroup(String name, String group) { return jobTaskRepository.findByNameAndGroup(name, group); } /** * 获取任务类实例 * @param className * @return * @throws Exception */ private Object getClass(String className) throws Exception { Class<?> clazz = Class.forName(className); return clazz.newInstance(); } /** * 实现 InitializingBean 接口,在启动应用时加载已存在的定时任务 * @throws Exception */ @Override public void afterPropertiesSet() throws Exception { List<JobTask> jobTaskList = jobTaskRepository.findAll(); for (JobTask jobTask : jobTaskList) { if (jobTask.getStatus() == 1) { addJobTask(jobTask); } } } } ``` 4. 创建定时任务的控制器类,用于处理新增、修改、删除等请求: ```java @RestController @AllArgsConstructor @RequestMapping("/job") public class JobTaskController { private final JobTaskService jobTaskService; /** * 添加任务 * @param jobTask * @return * @throws Exception */ @PostMapping public ResponseEntity addJobTask(@RequestBody JobTask jobTask) throws Exception { boolean result = jobTaskService.addJobTask(jobTask); return result ? ResponseEntity.ok("任务添加成功") : ResponseEntity.badRequest().body("任务添加失败"); } /** * 修改任务 * @param jobTask * @return * @throws Exception */ @PutMapping public ResponseEntity modifyJobTask(@RequestBody JobTask jobTask) throws Exception { boolean result = jobTaskService.modifyJobTask(jobTask); return result ? ResponseEntity.ok("任务修改成功") : ResponseEntity.badRequest().body("任务修改失败"); } /** * 删除任务 * @param name * @param group * @return * @throws Exception */ @DeleteMapping("/{name}/{group}") public ResponseEntity deleteJobTask(@PathVariable String name, @PathVariable String group) throws Exception { boolean result = jobTaskService.deleteJobTask(name, group); return result ? ResponseEntity.ok("任务删除成功") : ResponseEntity.badRequest().body("任务删除失败"); } /** * 获取所有任务 * @return */ @GetMapping public ResponseEntity getAllJobTask() { List<JobTask> jobTaskList = jobTaskService.getAllJobTask(); return ResponseEntity.ok(jobTaskList); } /** * 根据任务名称和分组获取任务信息 * @param name * @param group * @return */ @GetMapping("/{name}/{group}") public ResponseEntity getJobTaskByNameAndGroup(@PathVariable String name, @PathVariable String group) { JobTask jobTask = jobTaskService.getJobTaskByNameAndGroup(name, group); return ResponseEntity.ok(jobTask); } } ``` 5. 创建定时任务的启动类,用于启动 SpringBoot 应用: ```java @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } /** * 注册定时任务调度器 * @return * @throws SchedulerException */ @Bean public SchedulerFactoryBean schedulerFactoryBean() throws SchedulerException { SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); Properties properties = new Properties(); properties.put("org.quartz.scheduler.instanceName", "ChitGPTScheduler"); properties.put("org.quartz.threadPool.threadCount", "10"); schedulerFactoryBean.setQuartzProperties(properties); schedulerFactoryBean.setStartupDelay(5); return schedulerFactoryBean; } /** * 注册定时任务实例 * @return */ @Bean public Scheduler scheduler() { return schedulerFactoryBean().getScheduler(); } } ``` 以上就是 SpringBoot 搭配 Quartz 实现动态定时任务的源码,希望能对您有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值