动态创建定时任务
大约 2 分钟languagejava
概述
通过继承 ScheduledTaskRegistrar 制作动态增删定时任务的工具类,第一次使用在 showa 项目中
源码
下面是动态工具类
package com.xdf.showa.utils;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.CronTask;
import org.springframework.scheduling.config.ScheduledTask;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class DynamicScheduledTaskRegistrar extends ScheduledTaskRegistrar {
private static final Logger logger = LoggerFactory.getLogger("dynamicScheduleTask");
private final Map<String, ScheduledTask> scheduledTaskMap = new LinkedHashMap<>(16);
public DynamicScheduledTaskRegistrar(){
super();
// 第二种实现方案
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(8);// 执行定时任务的线程数量
taskScheduler.setRemoveOnCancelPolicy(true);// 被取消的任务会被自动移除,防止尸位素餐
taskScheduler.setThreadNamePrefix("dynamic-scheduled-task-");// 定时任务线程池中线程名称的前缀
taskScheduler.initialize();
this.setScheduler(taskScheduler);
}
/**
* 新增任务
* @param taskName
* @param cron
* @param runnable
*/
public Boolean addCronTask(String taskName,String cron,Runnable runnable){
if(scheduledTaskMap.containsKey(taskName)){
logger.error("定时任务["+ taskName+"]已存在,添加失败");
return Boolean.FALSE;
}
CronTask cronTask = new CronTask(runnable,cron);
ScheduledTask scheduledTask = this.scheduleCronTask(cronTask);
scheduledTaskMap.put(taskName,scheduledTask);
logger.info("定时任务["+taskName+","+cron+"]新增成功");
return Boolean.TRUE;
}
/**
* 删除指定名称的定时任务
* @param taskName
*/
public void cancelCronTask(String taskName){
ScheduledTask scheduledTask = scheduledTaskMap.get(taskName);
if(null != scheduledTask){
scheduledTask.cancel();
scheduledTaskMap.remove(taskName);
}
logger.info("定时任务["+taskName+"]删除成功");
}
// 销毁所有定时任务
@Override
public void destroy() {
super.destroy();
scheduledTaskMap.values().forEach(ScheduledTask::cancel);
logger.info("已销毁所有定时任务");
}
// 返回所有任务的名称构成的字符串集合
public List<String> getAllTaskName(){
return scheduledTaskMap.keySet().stream().collect(Collectors.toList());
}
}
下面介绍使用方法
private final DynamicScheduledTaskRegistrar dynamicScheduledTaskRegistrar = new DynamicScheduledTaskRegistrar();
String taskName = "定时任务01";
String cron = "01 45 10 * * ?";// 每天10:45:01执行一次
dynamicScheduledTaskRegistrar.addCronTask(taskName,cron,() -> { System.out.println("执行了定时任务") });
也可以纳入 spring 容器后通过自动注入使用,在项目中新增自定义配置类创建动态任务注册类对象并纳入 spring 容器
package com.xdf.wxpad.config;
import com.xdf.wxpad.util.DynamicScheduledTaskRegistrar;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CustomizeConfigure {
// 动态定时任务工具纳入spring容器
@Bean("dynamicScheduledTaskRegistrar")
public DynamicScheduledTaskRegistrar initTaskRegistrar(){
return new DynamicScheduledTaskRegistrar();
}
}
注意
如代码 dynamicScheduledTaskRegistrar.addCronTask(taskName,cron,() -> remindPriorityMain(priorityMain)); 执行定时任务时传入了对象 priorityMain 可能会有状态过期的问题。比如在创建定时任务时对象 priorityMain 的进度是正在处理,而在第二天执行任务时该任务已经在前一天设置 验收合格 了,此时不应该再发送邮件通知担当者,所以定时任务的传入参数应该是任务的主键,在执行任务时使用主键重新查询最新的业务数据,拿到最新状态后再决定是否要发送邮件。
