springboot项目 TaskScheduler 实现动态插入定时任务

本文介绍了如何在SpringBoot项目中使用@EnableScheduling注解启动定时任务,配置ThreadPoolTaskScheduler,创建数据库表存储定时任务信息,以及如何在项目启动时初始化和管理这些定时任务。还涉及了TimerTaskService接口和其实现类的操作,如添加、更新和删除任务,以及根据Cron表达式进行定时执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.启动类打开

@EnableScheduling 注解

2. 创建定时任务线程池配置

@Configuration
public class SchedulingConfig {
    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        // 定时任务执行线程池核心线程数
        taskScheduler.setPoolSize(6);
        taskScheduler.setRemoveOnCancelPolicy(true);
        taskScheduler.setThreadNamePrefix("TaskSchedulerThreadPool-");
        return taskScheduler;
    }
}

3.创建数据库表,用来保存定时任务详情,调度等信息


@Data
@EqualsAndHashCode(callSuper = false)
public class TimerTask implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 任务id
     */
    @TableId
    private Long taskId;

    /**
     * 任务表达式
     */
    private String taskCron;

    /**
     * 任务描述
     */
    private String taskDesc;

    /**
     * 任务类名
     */
    private String beanName;

    /**
     * 任务名称
     */
    private String methodName;

    /**
     * 任务参数
     */
    private String methodParams;

    /**
     * 任务状态 0开启 1关闭
     */
    private int taskEnable;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 修改时间
     */
    private Date modifyTime;


}

4.项目启动后初始化定时任务,(tasks就是保存在数据库表里的所有定时任务)

@Slf4j
@Component
public class SchedulingRunnable implements CommandLineRunner {

    @Autowired
    private TimerTaskService taskService;

    @Override
    public void run(String... args) {
        List<TimerTask> tasks = taskService.list();
        for (TimerTask task : tasks) {
            if (task.getTaskEnable() == 0) {
                taskService.scheduleTask(task);
            }
        }
        log.info("定时任务初始化成功!!!");
    }

}

5.TimerTaskService ,实现定时任务的添加,取消等业务

public interface TimerTaskService extends IService<TimerTask> {

    void addTask(TimerTask task);

    void updateTask(TimerTask task);

    void delTask(Long taskId);

    void scheduleTask(TimerTask task);
}
package com.ly.mk.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ly.mk.entity.TimerTask;
import com.ly.mk.mapper.TimerTaskMapper;
import com.ly.mk.service.TimerTaskService;
import com.ly.mk.util.SpringContextUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;


@Slf4j
@Service
public class TimerTaskServiceImpl extends ServiceImpl<TimerTaskMapper, TimerTask> implements TimerTaskService {

    @Autowired
    private TaskScheduler taskScheduler;

    private Map<Long, ScheduledFuture<?>> scheduledFutureMap = new ConcurrentHashMap<>();

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addTask(TimerTask task) {
        task.setCreateTime(new Date());
        this.save(task);
        if (task.getTaskEnable() == 0) {
            scheduleTask(task);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTask(TimerTask task) {
        //更新数据库
        task.setModifyTime(new Date());
        this.updateById(task);
        //先删除
        cancelTask(task.getTaskId());
        //开启定时任务
        if (task.getTaskEnable() == 0) {
            scheduleTask(task);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delTask(Long taskId) {
        this.removeById(taskId);
        cancelTask(taskId);
    }

    private void cancelTask(Long taskId) {
        ScheduledFuture<?> scheduledFuture = scheduledFutureMap.get(taskId);
        if (Objects.nonNull(scheduledFuture))
            scheduledFuture.cancel(true);
        // 如果任务取消需要消耗点时间
        boolean cancelled = scheduledFuture.isCancelled();
        while (!cancelled) {
            scheduledFuture.cancel(true);
        }
        // 最后从队列中删除
        scheduledFutureMap.remove(taskId);
    }

    //定时任务添加到任务队列
    public void scheduleTask(TimerTask task) {
        scheduledFutureMap.put(task.getTaskId(), taskScheduler.schedule(createRunnableTask(task), new CronTrigger(task.getTaskCron())));
    }

    private Runnable createRunnableTask(TimerTask task) {
        return () -> {
            Object target = SpringContextUtils.getBean(lowerFirstCapse(task.getBeanName()));
            Method method;
            String methodName = task.getMethodName();
            String methodParams = task.getMethodParams();
            try {
                if (StringUtils.isNotBlank(methodName)) {
                    method = target.getClass().getDeclaredMethod(methodName, String.class);
                } else {
                    method = target.getClass().getDeclaredMethod(methodName);
                }
                ReflectionUtils.makeAccessible(method);
                if (StringUtils.isNotBlank(methodParams)) {
                    method.invoke(target, methodParams);
                } else {
                    method.invoke(target);
                }
            } catch (Exception e) {
                e.printStackTrace();
                log.error(String.format("定时任务执行异常 - bean:%s,方法:%s,参数:%s ", task.getBeanName(), methodName, methodParams), e);
            }
        };
    }

    /**
     * 转换首字母小写
     *
     * @param str
     * @return
     */
    public static String lowerFirstCapse(String str) {
        char[] chars = str.toCharArray();
        chars[0] += 32;
        return String.valueOf(chars);
    }

}

6.根据自己的业务需求创建自己的定时任务实现类,实现具体逻辑

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值