TaskScheduler动态定时任务

定时任务的编写,在 Spring 里常见的两种方式:

  1. @Scheduled 注解 → 静态配置,启动时就确定了,不能动态改。

  2. 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 {

    @Bean
    public 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
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐