【SpringBoot】@Scheduled是静态配置,是我想改时间,但又不想引入其他组件,还有什么方案么?
TaskScheduler动态定时任务
定时任务的编写,在 Spring 里常见的两种方式:
-
@Scheduled
注解 → 静态配置,启动时就确定了,不能动态改。 -
TaskScheduler
→ 可以在运行时动态添加 / 修改 / 取消任务。
示例代码
任务可以存储在数据库,这里用map模拟。
import lombok.Data;@Data
public class TaskRequest {private String taskId;private String cron;private String beanName; // Bean 名称private String methodName; // 方法名
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;@Configuration
public class SchedulerConfig {@Beanpublic ThreadPoolTaskScheduler taskScheduler() {ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();scheduler.setPoolSize(5);scheduler.setThreadNamePrefix("dynamic-task-");scheduler.initialize();return scheduler;}
}
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;@Component
public class DynamicTaskManager {private final TaskScheduler taskScheduler;private final ApplicationContext applicationContext;private final Map<String, ScheduledFuture<?>> taskMap = new ConcurrentHashMap<>();public DynamicTaskManager(TaskScheduler taskScheduler, ApplicationContext applicationContext) {this.taskScheduler = taskScheduler;this.applicationContext = applicationContext;}// 添加任务public void addTask(String taskId, String cron, String beanName, String methodName) {if (taskMap.containsKey(taskId)) {throw new IllegalArgumentException("任务已存在: " + taskId);}Runnable task = () -> {try {Object bean = applicationContext.getBean(beanName);Method method = bean.getClass().getMethod(methodName);method.invoke(bean);} catch (Exception e) {e.printStackTrace();}};ScheduledFuture<?> future = taskScheduler.schedule(task, new CronTrigger(cron));taskMap.put(taskId, future);}public void removeTask(String taskId) {ScheduledFuture<?> future = taskMap.remove(taskId);if (future != null) {future.cancel(true);}}public void updateTask(String taskId, String cron, String beanName, String methodName) {removeTask(taskId);addTask(taskId, cron, beanName, methodName);}public boolean hasTask(String taskId) {return taskMap.containsKey(taskId);}public Map<String, Boolean> listTasks() {Map<String, Boolean> result = new ConcurrentHashMap<>();taskMap.forEach((id, f) -> result.put(id, !f.isCancelled()));return result;}
}
import org.springframework.stereotype.Component;@Component("myTaskBean")
public class MyTaskMethods {public void sendEmail() {System.out.println("发送邮件任务执行了:" + new java.util.Date());}public void cleanCache() {System.out.println("清理缓存任务执行了:" + new java.util.Date());}public void generateReport() {System.out.println("生成报表任务执行了:" + new java.util.Date());}
}
import org.springframework.web.bind.annotation.*;import java.util.Map;@RestController
@RequestMapping("/tasks")
public class TaskController {private final DynamicTaskManager taskManager;public TaskController(DynamicTaskManager taskManager) {this.taskManager = taskManager;}@PostMapping("/add")public String addTask(@RequestBody TaskRequest request) {taskManager.addTask(request.getTaskId(), request.getCron(),request.getBeanName(), request.getMethodName());return "任务添加成功: " + request.getTaskId();}@PostMapping("/update")public String updateTask(@RequestBody TaskRequest request) {taskManager.updateTask(request.getTaskId(), request.getCron(),request.getBeanName(), request.getMethodName());return "任务更新成功: " + request.getTaskId();}@DeleteMapping("/remove/{taskId}")public String removeTask(@PathVariable String taskId) {taskManager.removeTask(taskId);return "任务删除成功: " + taskId;}@GetMapping("/list")public Map<String, Boolean> listTasks() {return taskManager.listTasks();}
}
调试示例代码
添加任务(调用 MyTaskMethods.sendEmail()
,每 5 秒执行一次)
POST http://localhost:8080/tasks/add
Content-Type: application/json{"taskId": "emailTask","cron": "*/5 * * * * *","beanName": "myTaskBean","methodName": "sendEmail"
}
更新任务(改成调用 cleanCache()
,每 10 秒执行一次)
POST http://localhost:8080/tasks/update
Content-Type: application/json{"taskId": "emailTask","cron": "*/10 * * * * *","beanName": "myTaskBean","methodName": "cleanCache"
}
删除任务
DELETE http://localhost:8080/tasks/remove/emailTask