SpringBoot集成动态定时任务

目标

一、数据库动态配置定时任务
二、项目启动时启动定时任务

详细代码

建立数据表
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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

技术宅老谢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值