目标
一、数据库动态配置定时任务
二、项目启动时启动定时任务
详细代码
建立数据表
CREATE TABLE `scheduled_task` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`task_key` varchar(128) NOT NULL COMMENT '任务key值(使用bean名称)',
`task_desc` varchar(128) DEFAULT NULL COMMENT '任务描述',
`task_cron` varchar(128) NOT NULL COMMENT '任务表达式',
`init_start_flag` int(2) NOT NULL DEFAULT '1' COMMENT '程序初始化是否启动 1 是 0 否',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='定时任务表';
建立定时任务数据
INSERT INTO `scheduled_task` VALUES ('1', 'scheduledTask01', '发货定时任务(每天凌晨1点启动)', '0 0 1 * * ?', '1', '2021-05-15 23:48:54', '2021-05-28 22:24:56');
INSERT INTO `scheduled_task` VALUES ('2', 'scheduledTask02', '退货定时任务(每天凌晨2点启动)', '0 0 2 * * ?', '1', '2021-05-15 23:48:54', '2021-05-28 22:24:57');
INSERT INTO `scheduled_task` VALUES ('3', 'scheduledTask03', '库存定时任务(每周二凌晨3点启动)', '0 0 3 ? * 2', '1', '2021-05-23 18:23:41', '2021-05-28 22:24:49');
INSERT INTO `scheduled_task` VALUES ('4', 'scheduledTask04', '库存定时任务(每月1号凌晨4点启动)', '0 0 4 1 * ?', '1', '2021-05-26 21:26:42', '2021-05-28 22:24:58');
ScheduledTaskJob
/**
* 调度任务公共父接口
*/
public interface ScheduledTaskJob extends Runnable {
}
ScheduledTask01
/**
* 定时任务01(每天凌晨1点,发送前一天的SO信息)
*/
public class ScheduledTask01 implements ScheduledTaskJob {
private static final Logger LOGGER = LoggerFactory.getLogger(ScheduledTask01.class);
@Override
public void run() {
}
}
ScheduledTaskService
/**
* 定时任务接口
*/
public interface ScheduledTaskService extends IService<ScheduledTask> {
/**
* 分页获取列表
* @param condition
* @return
*/
List<Map<String, Object>> list(String condition);
/**
* 所有任务列表
*/
List<ScheduledTask> taskList();
/**
* 根据任务key 启动任务
*/
Boolean start(String taskKey);
/**
* 根据任务key 停止任务
*/
Boolean stop(String taskKey);
/**
* 根据任务key 重启任务
*/
Boolean restart(String taskKey);
/**
* 程序启动时初始化 ==> 启动所有正常状态的任务
*/
void initAllTask(List<ScheduledTask> scheduledTaskList);
}
ScheduledTaskServiceImpl
/**
* <p>
* 定时任务实现类
* </p>
*
*/
@Service
public class ScheduledTaskServiceImpl extends ServiceImpl<ScheduledTaskMapper, ScheduledTask> implements ScheduledTaskService {
/**
* 日志
*/
private static final Logger LOGGER = LoggerFactory.getLogger(ScheduledTaskServiceImpl.class);
@Autowired
private ScheduledTaskMapper scheduledTaskMapper;
/**
* 可重入锁
*/
private ReentrantLock lock = new ReentrantLock();
/**
* 定时任务线程池
*/
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
/**
* 所有定时任务存放Map
* key :任务 key
* value:任务实现
*/
@Autowired
@Qualifier(value = "scheduledTaskJobMap")
private Map<String, ScheduledTaskJob> scheduledTaskJobMap;
/**
* 存放已经启动的任务map
*/
private Map<String, ScheduledFuture> scheduledFutureMap = new ConcurrentHashMap<>();
/**
* 分页获取列表
* @param condition
* @return
*/
@Override
public List<Map<String, Object>> list(String condition) {
return scheduledTaskMapper.list(condition);
}
/**
* 所有任务列表
*/
@Override
public List<ScheduledTask> taskList() {
LOGGER.info(">>>>>> 获取任务列表开始 >>>>>> ");
//数据库查询所有任务 => 未做分页
List<ScheduledTask> taskBeanList = scheduledTaskMapper.getAllTask();
if (CollectionUtils.isEmpty(taskBeanList)) {
return new ArrayList<>();
}
for (ScheduledTask taskBean : taskBeanList) {
String taskKey = taskBean.getTaskKey();
//是否启动标记处理
taskBean.setInitStartFlag(this.isStart(taskKey));
}
LOGGER.info(">>>>>> 获取任务列表结束 >>>>>> ");
return taskBeanList;
}
/**
* 根据任务key 启动任务
*
* @param taskKey
*/
@Override
public Boolean start(String taskKey) {
LOGGER.info(">>>>>> 启动任务 {} 开始 >>>>>>", taskKey);
//添加锁放一个线程启动,防止多人启动多次
lock.lock();
LOGGER.info(">>>>>> 添加任务启动锁完毕");
try {
//校验是否已经启动
if (this.isStart(taskKey)==1) {
LOGGER.info(">>>>>> 当前任务已经启动,无需重复启动!");
return false;
}
//校验任务是否存在
if (!scheduledTaskJobMap.containsKey(taskKey)) {
return false;
}
//根据key数据库获取任务配置信息
ScheduledTask scheduledTask = scheduledTaskMapper.getByKey(taskKey);
//启动任务
this.doStartTask(scheduledTask);
} finally {
// 释放锁
lock.unlock();
LOGGER.info(">>>>>> 释放任务启动锁完毕");
}
LOGGER.info(">>>>>> 启动任务 {} 结束 >>>>>>", taskKey);
return true;
}
/**
* 根据任务key 停止任务
*
* @param taskKey
*/
@Override
public Boolean stop(String taskKey) {
LOGGER.info(">>>>>> 进入停止任务 {} >>>>>>", taskKey);
//当前任务实例是否存在
boolean taskStartFlag = scheduledFutureMap.containsKey(taskKey);
LOGGER.info(">>>>>> 当前任务实例是否存在 {}", taskStartFlag);
if (taskStartFlag) {
//获取任务实例
ScheduledFuture scheduledFuture = scheduledFutureMap.get(taskKey);
//关闭实例
scheduledFuture.cancel(true);
}
LOGGER.info(">>>>>> 结束停止任务 {} >>>>>>", taskKey);
return taskStartFlag;
}
/**
* 根据任务key 重启任务
*
* @param taskKey
*/
@Override
public Boolean restart(String taskKey) {
LOGGER.info(">>>>>> 进入重启任务 {} >>>>>>", taskKey);
//先停止
this.stop(taskKey);
//再启动
return this.start(taskKey);
}
/**
* 程序启动时初始化 ==> 启动所有正常状态的任务
*
* @param scheduledTaskList
*/
@Override
public void initAllTask(List<ScheduledTask> scheduledTaskList) {
LOGGER.info("程序启动 ==> 初始化所有任务开始 !size={}", scheduledTaskList.size());
if (CollectionUtils.isEmpty(scheduledTaskList)) {
return;
}
for (ScheduledTask scheduledTask : scheduledTaskList) {
//任务 key
String taskKey = scheduledTask.getTaskKey();
//校验是否已经启动
if (this.isStart(taskKey)==1) {
continue;
}
//启动任务
this.doStartTask(scheduledTask);
}
LOGGER.info("程序启动 ==> 初始化所有任务结束 !size={}", scheduledTaskList.size());
}
/**
* 执行启动任务
*/
private void doStartTask(ScheduledTask scheduledTask) {
//任务key
String taskKey = scheduledTask.getTaskKey();
//定时表达式
String taskCron = scheduledTask.getTaskCron();
//获取需要定时调度的接口
ScheduledTaskJob scheduledTaskJob = scheduledTaskJobMap.get(taskKey);
LOGGER.info(">>>>>> 任务 [ {} ] ,cron={}", scheduledTask.getTaskDesc(), taskCron);
ScheduledFuture scheduledFuture = threadPoolTaskScheduler.schedule(scheduledTaskJob,
new Trigger() {
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
CronTrigger cronTrigger = new CronTrigger(taskCron);
return cronTrigger.nextExecutionTime(triggerContext);
}
});
//将启动的任务放入 map
scheduledFutureMap.put(taskKey, scheduledFuture);
}
/**
* 任务是否已经启动
*/
private Integer isStart(String taskKey) {
//校验是否已经启动
if (scheduledFutureMap.containsKey(taskKey)) {
if (!scheduledFutureMap.get(taskKey).isCancelled()) {
return 1;
}
}
return 0;
}
}
ScheduledTaskEnum
/**
* 定时任务枚举值
* 注:key 需要与数据库保持一致
*/
public enum ScheduledTaskEnum {
/**
* 任务1
*/
TASK_01("scheduledTask01", new ScheduledTask01()),
/**
* 任务2
*/
TASK_02("scheduledTask02", new ScheduledTask02()),
/**
* 任务3
*/
TASK_03("scheduledTask03", new ScheduledTask03()),
/**
* 任务4
*/
TASK_04("scheduledTask04", new ScheduledTask04())
;
/**
* 定时任务key
*/
private String taskKey;
/**
* 定时任务 执行实现类
*/
private ScheduledTaskJob scheduledTaskJob;
ScheduledTaskEnum(String taskKey, ScheduledTaskJob scheduledTaskJob) {
this.taskKey = taskKey;
this.scheduledTaskJob = scheduledTaskJob;
}
/**
* 初始化 所有任务
*/
public static Map<String, ScheduledTaskJob> initScheduledTask() {
if (ScheduledTaskEnum.values().length < 0) {
return new ConcurrentHashMap<>();
}
Map<String, ScheduledTaskJob> scheduledTaskJobMap = new ConcurrentHashMap<>();
for (ScheduledTaskEnum taskEnum : ScheduledTaskEnum.values()) {
scheduledTaskJobMap.put(taskEnum.taskKey, taskEnum.scheduledTaskJob);
}
return scheduledTaskJobMap;
}
}