springboot动态添加定时任务

springboot动态添加定时任务

引用(感谢)

https://blog.csdn.net/iT_MaNongking/article/details/145305954?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-4-145305954-blog-125277410.235^v43^pc_blog_bottom_relevance_base2&spm=1001.2101.3001.4242.3&utm_relevant_index=6

感谢原博主

本文共展示两种方式

  • 延迟任务,只执行一次的任务
  • 需要动态扩展,执行多次的任务

一、延迟执行,只执行一次的任务

import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

    @Resource
    ThreadPoolTaskScheduler syncScheduler;
    
    /**
     * batch: 业务数据
     */
     public void addSchedule(Batch batch) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MINUTE, batch.getUpgradeTime());
        // schedule :调度给定的Runnable ,在指定的执行时间调用它。
        //一旦调度程序关闭或返回的ScheduledFuture被取消,执行将结束。
        //参数:
        //任务 – 触发器触发时执行的 Runnable
        //startTime – 任务所需的执行时间(如果这是过去,则任务将立即执行,即尽快执行)
        Date startTime = calendar.getTime();
        ScheduledFuture<?> schedule = syncScheduler.schedule(
                getRunnable(batch.getBatchId()), calendar.getTime());
    }
    
    /**
     * batchId: 业务数据
     */
      public Runnable getRunnable(Long batchId) {
        return () -> {
            // 实现业务逻辑
            stop(batchId);
        };
    }

二、需要动态执行的任务

随时新增、删除;

修改时间:我这里的逻辑就是删除旧的任务,再新增新的任务

配置类,固定信息不用改


import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.config.CronTask;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import java.util.concurrent.ScheduledFuture;

/**
 * @description: 添加定时任务注册类,用来增加、删除定时任务。
 **/
@Component
public class CronTaskRegistrar implements DisposableBean {

    public static final Map<Runnable, ScheduledFuture<?>> scheduledTasks = new ConcurrentHashMap<>();
    public static final Map<Long, Runnable> runnableMap = new ConcurrentHashMap<>();

    @Autowired
    private TaskScheduler taskScheduler;

    public TaskScheduler getScheduler() {
        return this.taskScheduler;
    }

    /**
     * 新增定时任务
     * @param task
     * @param cronExpression
     */
    public  void addCronTask(Runnable task, String cronExpression) {
        addCronTask(new CronTask(task, cronExpression));
    }

    public void addCronTask(CronTask cronTask) {
        if (cronTask != null) {
            Runnable task = cronTask.getRunnable();
            if (scheduledTasks.containsKey(task)) {
                removeCronTask(task);
            }
            scheduledTasks.put(task, scheduleCronTask(cronTask));
        }
    }


    /**
     * @description: 移除定时任务
     */
    public void removeCronTask(Runnable task) {
        ScheduledFuture<?> scheduledTask = scheduledTasks.get(task);
        if (scheduledTask != null) {
            scheduledTask.cancel(true);
            scheduledTasks.remove(task);
        }
    }

    public ScheduledFuture<?> scheduleCronTask(CronTask cronTask) {
        return this.taskScheduler.schedule(cronTask.getRunnable(), cronTask.getTrigger());
    }

    /**
    * @description: 定时任务销毁
    */
    @Override
    public void destroy() {
        for (ScheduledFuture<?> task : scheduledTasks.values()) {
            task.cancel(true);
        }
        scheduledTasks.clear();
    }
}


固定信息不用改

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;

@Configuration
public class SchedulerConfig {

    @Bean()
    public TaskScheduler taskScheduler() {
        return new ConcurrentTaskScheduler();
    }
}

获取bean的,固定信息不用改

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringContextUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        applicationContext = context;
    }

    public static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }

    public static Object getBean(String name) {
        return applicationContext.getBean(name);
    }
}

业务实现类,需要改

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;

@Slf4j
public class SchedulingRunnable implements Runnable {
	
	// TODO 对象需要改,也就是定时任务需要处理的东西
    private TTagPO tag;

    public SchedulingRunnable(TTagPO tag) {
        this.tag = tag;
    }

    @Override
    public void run() {
        try {
        	// 通过反射调用需要执行业务的方法,参数也可以放在当前类的构造方法中,写死也可以
            Object target = SpringContextUtil.getBean("类名");
            // 方法的参数多的话,就是用 ... 这个东西
            Method method = target.getClass().getDeclaredMethod("方法名", 方法的参数.class);
            ReflectionUtils.makeAccessible(method);
            method.invoke(target, tag);
        } catch (Exception ex) {
            log.error("定时任务执行失败,tag_id:{}", tag.getId(), ex);
        }
    }
}

业务实现类需要改

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ylzinfo.brt.constant.GlobalConstant;
import com.ylzinfo.brt.entity.TTagPO;
import com.ylzinfo.brt.service.impl.TTagServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;

/**
 * 项目启动后加载动态定时任务
 */
@Slf4j
@Component
public class JobsLoader implements ApplicationRunner {

    @Autowired
    private CronTaskRegistrar cronTaskRegistrar;
    @Resource
    private TTagServiceImpl tagService;

	// 第一个 %s 为分钟;第二个为小时;第三个为天
	// 假如一二三参数分别为:15、17、3;就表示:每个月从一号开始算每3天的17点15分执行一次任务
	// 具体的执行日期看个人需求
    public static final String CRON = "0 %s %s 1/%s * ?";

	// 业务方法,获取定时任务执行的时间的
    public static String getCron(String cycleTime, Integer cycleDay){
        String[] split = cycleTime.split(":");
        return String.format(CRON, split[1], split[0], cycleDay.toString());
    }

    /**
     * 项目启动后加载动态定时任务
     * @param args
     * @throws Exception
     */
    @Override
    public void run(ApplicationArguments args) throws Exception {
        ttsTaskLoader();
    }

    /**
    * @description: 加载定时发送任务
    * @create: 2025/01/10 15:50
    * @param:
    * @return:
    */
    public void ttsTaskLoader() {
        // 项目启动时,初始化定时器
        // 业务方法,获取需要加载到定时任务的
        List<TTagPO> list = tagService.list();
        for (TTagPO tag : list) {
            SchedulingRunnable task = new SchedulingRunnable(tag);
            cronTaskRegistrar.addCronTask(task, getCron(tag.getCycleTime(), tag.getCycleDay()));
            CronTaskRegistrar.runnableMap.put(tag.getId(), task);
        }
    }

}


新增定时任务、删除定时任务

    @Resource
    private CronTaskRegistrar cronTaskRegistrar;
 
 /**
     * 新增动态定时任务
     * @param tag
     * @param cycleTime
     * @param cycleDay
     */
    public void addSchedule(TTagPO tag, String cycleTime, Integer cycleDay){
        SchedulingRunnable task = new SchedulingRunnable(tag);
        cronTaskRegistrar.addCronTask(task, JobsLoader.getCron(cycleTime, cycleDay));
        CronTaskRegistrar.runnableMap.put(tag.getId(), task);
    }

    /**
     * 删除定时任务
     * @param id
     */
    public void removeSchedule(Long id){
        cronTaskRegistrar.removeCronTask(CronTaskRegistrar.runnableMap.get(id));
        CronTaskRegistrar.runnableMap.remove(id);
    }
posted @ 2025-05-22 21:39  窃窃私语QAQ  阅读(24)  评论(0)    收藏  举报