在Springboot中,当多个类同时实现SchedulingConfigurer
接口时,导致定时任务不执行或者部分不执行的原因是:
在Springboot中ScheduledTaskRegistrar
是一个共享对象,多个类在 configureTasks 方法中修改它时,可能会相互覆盖对方的任务配置。
为什么会覆盖对方的注册任务呢?
是因为如下代码,在多个类中同时执行了:
taskRegistrar.setTriggerTasks(triggerTasks);
导致定时任务被覆盖。
解决方式:将上面代码改成如下即可:
taskRegistrar.addTriggerTask(new TriggerTask(new TaskRunnable(task), new TaskTrigger(task)));
在ScheduledTaskRegistrar
类中,taskRegistrar.setTriggerTasks(triggerTasks);
与taskRegistrar.addTriggerTask(new TaskRunnable(task), new TaskTrigger(task));
重点区别在于,setTriggerTasks()每次设置时都会重新创建一个list,而addTriggerTask()会重新判断,如果为空,才重新创建
// 在org.springframework.scheduling.config.ScheduledTaskRegistrar 中
public void setTriggerTasks(Map<Runnable, Trigger> triggerTasks) {
// 每次都会重新new一个新的对象
this.triggerTasks = new ArrayList();
triggerTasks.forEach((task, trigger) -> {
this.addTriggerTask(new TriggerTask(task, trigger));
});
}
public void addTriggerTask(Runnable task, Trigger trigger) {
this.addTriggerTask(new TriggerTask(task, trigger));
}
public void addTriggerTask(TriggerTask task) {
// 每次会重新判断,如果为空,才重新创建
if (this.triggerTasks == null) {
this.triggerTasks = new ArrayList();
}
this.triggerTasks.add(task);
}
定时任务实现代码
@Component
public class TaskSchedule implements SchedulingConfigurer{
final TaskService taskService;
public TaskSchedule(TaskService taskService) {
this.taskService = taskService;
}
private void registrarTasks(ScheduledTaskRegistrar taskRegistrar) {
// Map<Runnable, Trigger> triggerTasks = new HashMap<>();
Filterable<Task> filterable = new Filterable<>();
Map<String, Object> filter = Maps.newHashMap();
filter.put("execService", "task-api");
filterable.setFilter(filter);
List<Task> taskConfigs = taskService.list(filterable);
for (Task task : taskConfigs) {
if (StringUtils.isBlank(task.getCron()))
continue;
if (task.getDeleted())
continue;
if (task.getStatus() == 0)
continue;
// triggerTasks.put(new TaskRunnable(task), new TaskTrigger(task));
// 注册任务
taskRegistrar.addTriggerTask(new TaskRunnable(task), new TaskTrigger(task));
}
// 重新设置任务 会清空triggerTasks中原来的任务
// taskRegistrar.setTriggerTasks(triggerTasks);
}
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
this.registrarTasks(taskRegistrar);
}
}
class TaskTrigger implements Trigger {
Task task;
public TaskTrigger(Task task) {
this.task = task;
}
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
CronTrigger trigger = new CronTrigger(task.getCron());
Date lastTime = triggerContext.lastScheduledExecutionTime();
Date nextDate = trigger.nextExecutionTime(triggerContext);
System.out.println(String.format("Task :%s Last Date:%s Next Date:%s ...", task.getId(), DateUtil.format(lastTime), DateUtil.format(nextDate)));
return nextDate;
}
}
class TaskRunnable implements Runnable {
Task task;
public TaskRunnable(Task task) {
this.task = task;
}
@Override
public void run() {
System.out.println("执行定时任务、、、、、、");
}
}