需求场景
最近我在工作当中遇到需要支持用户在前端界面上动态配置定时任务的执行时间和执行参数的需求。在我们平时的开发当中,传统的方式就是在类的方法上使用注解@Scheduled(cron = “0 0 0 1 * ?”)这样来配置时任务,但是不能够满足我们的需求,不能动态配置和改变任务的执行时间和执行参数。我们需要怎么做?接下来我们来实现一下
上才艺
目录结构
DemoApplication
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
TaskController
package com.example.demo.controller;
import com.example.demo.service.TaskService;
import com.example.demo.task.ScheduleTask;
import com.example.demo.utils.ScheduleUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* 控制器
*
* @author zhongxiaojian
* @date 2020/8/14
**/
@RestController
@RequestMapping("task")
public class TaskController {
@Autowired
private TaskService service;
/**
* 新增或者修改
*
* @param id 任务ID
* @param cron 执行时间表达式
* @param keyword 关键字参数
* @return true or false
*/
@PostMapping("saveOrEdit")
public boolean saveOrEdit(@RequestParam("id") String id,
@RequestParam("cron") String cron,
@RequestParam("keyword") String keyword) {
return ScheduleUtil.reset(new ScheduleTask(id, service, keyword), cron);
}
}
TaskService & TaskServiceImpl
package com.example.demo.service;
/**
* 任务处理
*
* @author zhongxiaojian
* @date 2020/8/14
**/
public interface TaskService {
/**
* 业务处理
*
* @param keyword 关键参数
*/
void work(String keyword);
}
package com.example.demo.service.impl;
import com.example.demo.service.TaskService;
import org.springframework.stereotype.Service;
/**
* @author zhongxiaojian
* @date 2020/8/14
**/
@Service
public class TaskServiceImpl implements TaskService {
@Override
public void work(String keyword) {
try {
//模拟业务逻辑
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
ScheduleTask
package com.example.demo.task;
import com.example.demo.service.TaskService;
/**
* 定时任务线程类
*
* @author zhongxiaojian
* @date 2020/4/17
**/
public class ScheduleTask implements Runnable {
private static final int TIMEOUT = 30000;
private String id;
private TaskService service;
private String keyword;
public String getId() {
return id;
}
/**
* @param id 任务ID
* @param service 业务类
* @param keyword 关键字参数
*/
public ScheduleTask(String id, TaskService service, String keyword) {
this.id = id;
this.service = service;
this.keyword = keyword;
}
@Override
public void run() {
service.work(keyword);
}
}
ScheduleUtil
package com.example.demo.utils;
import com.example.demo.task.ScheduleTask;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
/**
* 定时任务工具类
*
* @author zhongxiaojian
* @date 2020/4/17
**/
public class ScheduleUtil {
private static ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
private static Map<String, ScheduledFuture<?>> scheduledFutureMap = new HashMap<>();
static {
threadPoolTaskScheduler.initialize();
System.out.println("定时任务线程池启动");
}
/**
* 启动
*
* @param scheduleTask 定时任务
* @param corn 执行时间表达式
*/
public static boolean start(ScheduleTask scheduleTask, String corn) {
System.out.println("启动定时任务线程 taskId " + scheduleTask.getId());
ScheduledFuture<?> scheduledFuture = threadPoolTaskScheduler
.schedule(scheduleTask, new CronTrigger(corn));
scheduledFutureMap.put(scheduleTask.getId(), scheduledFuture);
return true;
}
/**
* 取消
*
* @param scheduleTask 定时任务
*/
public static boolean cancel(ScheduleTask scheduleTask) {
System.out.println("关闭定时任务线程 taskId " + scheduleTask.getId());
ScheduledFuture<?> scheduledFuture = scheduledFutureMap.get(scheduleTask.getId());
if (scheduledFuture != null && !scheduledFuture.isCancelled()) {
scheduledFuture.cancel(false);
}
scheduledFutureMap.remove(scheduleTask.getId());
return true;
}
/**
* 修改
*
* @param scheduleTask 定时任务
* @param corn 执行时间表达式
*/
public static boolean reset(ScheduleTask scheduleTask, String corn) {
//先取消定时任务
cancel(scheduleTask);
//然后启动新的定时任务
start(scheduleTask, corn);
return true;
}
}
总结
这样我们就完成了动态添加定时任务的接口,这里留了一个小小的问题,系统程序重启之后怎么办?其实也简单,只要把创建的任务的参数持久化到数据库,然后每次程序启动的时候读取出来初始化一遍就OK了,如果还不知道怎么办的同学就关注下方的公众号加小编的微信,小编手把手教你,包教包会。—————END—————
喜欢本文的朋友,欢迎关注公众号 BUG速递,分享程序员每天写出来的bug或工作中的问题