org.quartz-scheduler
quartz-jobs
2.3.2
org.quartz-scheduler
quartz
2.3.2
org.springframework.boot
spring-boot-starter-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;
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 jobClass = (Class) (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 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 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 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
根据自身需求创建一个用于前端调用后台接口传参的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 list = taskMapper.listTasks();
for(TaskDTO task : list) {
if (task.getJobStatus() == TaskStatusEnum.NORMAL.getCode()) {
quartzJobManager.resumeJob(task.getJobName(), task.getJobGroup());
}
}
}
}
TaskMapper.xml
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}
)
update qrtz_task
job_name = #{jobName},
job_group = #{jobGroup},
cron_expression = #{cronExpression},
job_class_name= #{jobClassName},
trigger_state= #{triggerState},
update_user = #{updateUser},
update_time = #{updateTime},
where id = #{id}
update qrtz_task
trigger_state= #{triggerState},
update_user = #{updateUser},
update_time = #{updateTime},
where id = #{id}
update qrtz_task
is_deleted = #{isDeleted},
update_user = #{updateUser},
update_time = #{updateTime},
where id = #{id}
整体pom.xml文件依赖配置
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.2.5.RELEASE
com.springcloud
dubbo_task
0.0.1-SNAPSHOT
dubbo_task
dubbo_task project for Spring Boot
UTF-8
UTF-8
1.8
Hoxton.SR3
2.2.1.RELEASE
3.3.0
2.9.2
com.springcloud
dubbo_api
0.0.1-SNAPSHOT
org.quartz-scheduler
quartz-jobs
2.3.2
org.quartz-scheduler
quartz
2.3.2
org.springframework.boot
spring-boot-starter-quartz
com.alibaba.cloud
spring-cloud-starter-dubbo
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
org.springframework.boot
spring-boot-starter-actuator
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-jdbc
mysql
mysql-connector-java
runtime
com.baomidou
mybatis-plus-boot-starter
${mybatis-plus.version}
org.projectlombok
lombok
true
io.springfox
springfox-swagger2
${swagger.version}
io.springfox
springfox-swagger-ui
${swagger.version}
org.apache.commons
commons-lang3
3.9
commons-beanutils
commons-beanutils
1.9.4
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
com.alibaba.cloud
spring-cloud-alibaba-dependencies
${spring-cloud-alibaba.version}
pom
import
org.springframework.boot
spring-boot-maven-plugin
涉及到微服务之间调用的定时任务
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