Spring Boot 动态定时任务:TaskScheduler 极简教程

TaskScheduler是Spring框架提供的任务调度接口,用于统一管理定时任务的触发与执行。它封装了不同的调度实现(如JDK的ScheduledThreadPoolExecutor、Quartz等),提供了丰富的调度方法,支持基于固定速率、固定延迟、Cron表达式等多种调度策略。

引言

在日常开发中,定时任务是常见的功能需求,例如数据同步、日志清理、报表生成等。传统的静态定时任务(如基于@Scheduled注解)虽然实现简单,但无法满足任务动态添加、修改、删除的场景。本文将详细介绍如何基于Spring Boot内置的TaskScheduler,实现一套灵活可扩展的动态定时任务系统,帮助开发者解决动态调度需求。

核心概念与原理

TaskScheduler 简介

TaskScheduler是Spring框架提供的任务调度接口,用于统一管理定时任务的触发与执行。它封装了不同的调度实现(如JDK的ScheduledThreadPoolExecutor、Quartz等),提供了丰富的调度方法,支持基于固定速率、固定延迟、Cron表达式等多种调度策略。

在Spring Boot中,当引入spring-context依赖(默认已包含在spring-boot-starter中)时,会自动配置ThreadPoolTaskScheduler(TaskScheduler的默认实现),无需额外引入第三方调度框架,降低了开发成本。

动态定时任务核心逻辑

动态定时任务的核心在于动态管理,即支持在应用运行过程中,对任务进行添加、更新、删除操作。其实现逻辑如下:

  • 任务存储:使用线程安全的容器(如ConcurrentHashMap)存储任务信息,确保多线程环境下的操作安全性。
  • 任务调度:通过TaskScheduler的schedule(Runnable task, Trigger trigger)方法,将任务与触发规则(如CronTrigger)绑定,返回ScheduledFuture对象用于后续任务控制。
  • 任务更新/删除:更新任务时,先通过旧任务的ScheduledFuture对象取消任务,再重新创建新任务并调度;删除任务时,直接通过ScheduledFuture取消任务并从容器中移除。

完整实现

任务实体类(ScheduledTask)

定义任务实体,存储任务的核心信息(任务ID、Cron表达式、描述、执行逻辑、调度结果等):

/**
 * 定时任务实体类
 * 封装任务信息、调度规则及调度结果
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ScheduledTask {
    // 任务唯一标识(用于动态管理)
    private String taskId;
    // 任务Cron表达式(调度规则)
    private String cronExpression;
    // 任务描述(备注信息)
    private String description;
    // 任务执行逻辑(Runnable接口实现)
    private Runnable task;
    // 调度结果(用于取消任务)
    private ScheduledFuture<?> scheduledFuture;

    /**
     * 构建任务执行逻辑
     * 可根据实际需求自定义任务内容
     */
    public void buildTask() {
        this.task = () -> {
            // 任务执行内容(示例:打印任务信息)
            System.out.printf("[%s] 动态定时任务执行 - 任务ID:%s,描述:%s%n",
                    System.currentTimeMillis(), taskId, description);
            // 实际业务逻辑可在此处扩展(如数据同步、文件处理等)
        };
    }

    /**
     * 基于Cron表达式创建触发规则
     * @return Trigger 触发规则
     */
    public Trigger buildTrigger() {
        return new CronTrigger(cronExpression);
    }

    /**
     * 调度任务(通过TaskScheduler执行)
     * @param taskScheduler 任务调度器
     */
    public void schedule(TaskScheduler taskScheduler) {
        this.scheduledFuture = taskScheduler.schedule(task, buildTrigger());
    }

    /**
     * 取消任务(停止调度)
     * @param mayInterruptIfRunning 是否允许中断正在执行的任务
     * @return boolean 取消结果(true:取消成功,false:取消失败)
     */
    public boolean cancelTask(boolean mayInterruptIfRunning) {
        if (scheduledFuture != null && !scheduledFuture.isCancelled()) {
            return scheduledFuture.cancel(mayInterruptIfRunning);
        }
        returnfalse;
    }
}
任务调度器配置(TaskSchedulerConfig)

配置ThreadPoolTaskScheduler,自定义线程池参数(如核心线程数、线程名称前缀等),确保任务调度的高效性和稳定性:

/**
 * 任务调度器配置类
 * 自定义ThreadPoolTaskScheduler参数,优化调度性能
 */
@Configuration
public class TaskSchedulerConfig {

    /**
     * 配置TaskScheduler实例
     * @return TaskScheduler 任务调度器
     */
    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        // 核心线程数(根据任务数量调整,避免线程过多导致资源浪费)
        taskScheduler.setPoolSize(5);
        // 线程名称前缀(便于日志排查)
        taskScheduler.setThreadNamePrefix("dynamic-task-scheduler-");
        // 任务拒绝策略(当线程池满时,直接抛出异常)
        taskScheduler.setRejectedExecutionHandler((runnable, executor) -> {
            throw new RuntimeException("任务调度线程池已满,无法执行新任务:" + runnable.getClass().getName());
        });
        // 初始化调度器(必须调用,否则无法生效)
        taskScheduler.initialize();
        return taskScheduler;
    }
}
任务管理器(TaskManager)

核心服务类,负责任务的添加、更新、删除、查询等动态管理操作,使用ConcurrentHashMap存储任务,确保线程安全:

/**
 * 定时任务管理器
 * 提供任务的动态管理(添加、更新、删除、查询)
 */
@Service
public class TaskManager {

    // 线程安全的任务容器(key:taskId,value:ScheduledTask)
    private final Map<String, ScheduledTask> taskMap = new ConcurrentHashMap<>();

    // 注入Spring配置的TaskScheduler
    @Autowired
    private TaskScheduler taskScheduler;

    /**
     * 添加定时任务
     * @param taskId 任务ID(唯一)
     * @param cronExpression Cron表达式
     * @param description 任务描述
     * @return boolean 添加结果(true:成功,false:任务已存在)
     */
    public boolean addTask(String taskId, String cronExpression, String description) {
        // 校验任务是否已存在
        if (taskMap.containsKey(taskId)) {
            System.out.printf("任务ID:%s 已存在,添加失败%n", taskId);
            returnfalse;
        }

        // 构建任务实例
        ScheduledTask task = new ScheduledTask();
        task.setTaskId(taskId);
        task.setCronExpression(cronExpression);
        task.setDescription(description);
        task.buildTask(); // 初始化任务执行逻辑

        // 调度任务
        task.schedule(taskScheduler);

        // 存入任务容器
        taskMap.put(taskId, task);
        System.out.printf("任务添加成功 - 任务ID:%s,Cron表达式:%s%n", taskId, cronExpression);
        returntrue;
    }

    /**
     * 更新任务的Cron表达式(修改调度规则)
     * @param taskId 任务ID
     * @param newCronExpression 新的Cron表达式
     * @return boolean 更新结果(true:成功,false:任务不存在)
     */
    public boolean updateTaskCron(String taskId, String newCronExpression) {
        // 校验任务是否存在
        ScheduledTask oldTask = taskMap.get(taskId);
        if (oldTask == null) {
            System.out.printf("任务ID:%s 不存在,更新失败%n", taskId);
            returnfalse;
        }

        // 1. 取消旧任务
        boolean cancelResult = oldTask.cancelTask(false);
        if (!cancelResult) {
            System.out.printf("任务ID:%s 取消失败,更新中断%n", taskId);
            returnfalse;
        }

        // 2. 创建新任务(复用旧任务的描述和执行逻辑,更新Cron表达式)
        ScheduledTask newTask = new ScheduledTask();
        newTask.setTaskId(taskId);
        newTask.setCronExpression(newCronExpression);
        newTask.setDescription(oldTask.getDescription());
        newTask.buildTask();

        // 3. 调度新任务
        newTask.schedule(taskScheduler);

        // 4. 替换任务容器中的旧任务
        taskMap.put(taskId, newTask);
        System.out.printf("任务更新成功 - 任务ID:%s,新Cron表达式:%s%n", taskId, newCronExpression);
        returntrue;
    }

    /**
     * 删除定时任务
     * @param taskId 任务ID
     * @return boolean 删除结果(true:成功,false:任务不存在)
     */
    public boolean deleteTask(String taskId) {
        // 校验任务是否存在
        ScheduledTask task = taskMap.get(taskId);
        if (task == null) {
            System.out.printf("任务ID:%s 不存在,删除失败%n", taskId);
            returnfalse;
        }

        // 1. 取消任务
        boolean cancelResult = task.cancelTask(false);
        if (!cancelResult) {
            System.out.printf("任务ID:%s 取消失败,删除中断%n", taskId);
            returnfalse;
        }

        // 2. 从容器中移除任务
        taskMap.remove(taskId);
        System.out.printf("任务删除成功 - 任务ID:%s%n", taskId);
        returntrue;
    }

    /**
     * 查询单个任务
     * @param taskId 任务ID
     * @return ScheduledTask 任务实例(null:任务不存在)
     */
    public ScheduledTask getTask(String taskId) {
        return taskMap.get(taskId);
    }

    /**
     * 查询所有任务
     * @return Collection<ScheduledTask> 所有任务列表
     */
    public Collection<ScheduledTask> getAllTasks() {
        return taskMap.values();
    }
}
控制器(TaskController)

提供RESTful接口,方便前端或其他服务调用,实现任务的动态管理:

/**
 * 定时任务API控制器
 * 提供RESTful接口,实现任务的动态管理
 */
@RestController
@RequestMapping("/api/tasks")
public class TaskController {

    @Autowired
    private TaskManager taskManager;

    /**
     * 添加任务
     * @param params 请求参数(taskId、cronExpression、description)
     * @return ResponseEntity<Map<String, Object>> 响应结果
     */
    @PostMapping
    public ResponseEntity<Map<String, Object>> addTask(@RequestBody Map<String, String> params) {
        Map<String, Object> result = new HashMap<>();
        try {
            // 校验参数
            String taskId = params.get("taskId");
            String cronExpression = params.get("cronExpression");
            String description = params.getOrDefault("description", "默认任务");
            if (taskId == null || cronExpression == null) {
                result.put("success", false);
                result.put("message", "任务ID和Cron表达式不能为空");
                return ResponseEntity.badRequest().body(result);
            }

            // 调用任务管理器添加任务
            boolean success = taskManager.addTask(taskId, cronExpression, description);
            result.put("success", success);
            result.put("message", success ? "任务添加成功" : "任务已存在");
            return ResponseEntity.ok(result);
        } catch (Exception e) {
            result.put("success", false);
            result.put("message", "任务添加失败:" + e.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
        }
    }

    /**
     * 更新任务Cron表达式
     * @param taskId 任务ID
     * @param params 请求参数(newCronExpression)
     * @return ResponseEntity<Map<String, Object>> 响应结果
     */
    @PutMapping("/{taskId}/cron")
    public ResponseEntity<Map<String, Object>> updateTaskCron(
            @PathVariable String taskId,
            @RequestBody Map<String, String> params) {
        Map<String, Object> result = new HashMap<>();
        try {
            // 校验参数
            String newCronExpression = params.get("newCronExpression");
            if (newCronExpression == null) {
                result.put("success", false);
                result.put("message", "新的Cron表达式不能为空");
                return ResponseEntity.badRequest().body(result);
            }

            // 调用任务管理器更新任务
            boolean success = taskManager.updateTaskCron(taskId, newCronExpression);
            result.put("success", success);
            result.put("message", success ? "任务Cron更新成功" : "任务不存在");
            return ResponseEntity.ok(result);
        } catch (Exception e) {
            result.put("success", false);
            result.put("message", "任务更新失败:" + e.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
        }
    }

    /**
     * 删除任务
     * @param taskId 任务ID
     * @return ResponseEntity<Map<String, Object>> 响应结果
     */
    @DeleteMapping("/{taskId}")
    public ResponseEntity<Map<String, Object>> deleteTask(@PathVariable String taskId) {
        Map<String, Object> result = new HashMap<>();
        try {
            // 调用任务管理器删除任务
            boolean success = taskManager.deleteTask(taskId);
            result.put("success", success);
            result.put("message", success ? "任务删除成功" : "任务不存在");
            return ResponseEntity.ok(result);
        } catch (Exception e) {
            result.put("success", false);
            result.put("message", "任务删除失败:" + e.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
        }
    }

    /**
     * 查询单个任务
     * @param taskId 任务ID
     * @return ResponseEntity<Map<String, Object>> 响应结果
     */
    @GetMapping("/{taskId}")
    public ResponseEntity<Map<String, Object>> getTask(@PathVariable String taskId) {
        Map<String, Object> result = new HashMap<>();
        try {
            ScheduledTask task = taskManager.getTask(taskId);
            if (task != null) {
                result.put("success", true);</doubaocanvas>

AI大模型学习福利

作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

一、全套AGI大模型学习路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获取

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获

三、AI大模型经典PDF籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。


因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获

四、AI大模型商业化落地方案

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获

作为普通人,入局大模型时代需要持续学习和实践,不断提高自己的技能和认知水平,同时也需要有责任感和伦理意识,为人工智能的健康发展贡献力量

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值