Java 动态添加 `Scheduled` 定时任务

举报
bug菌 发表于 2024/12/31 10:04:37 2024/12/31
【摘要】 🏆本文收录于「滚雪球学SpringBoot」专栏,专业攻坚指数级提升持续更新中,up!up!up!!欢迎点赞&&收藏&&订阅。@TOC ✨ 前言在 Java 应用中,定时任务是一个非常常见的需求。Spring 提供了 @Scheduled 注解用于配置静态的定时任务,但某些场景下,我们需要动态地添加或移除定时任务,例如基于用户的配置、动态时间间隔调整等。本文将深入解析如何在 Spring ...

🏆本文收录于「滚雪球学SpringBoot」专栏,专业攻坚指数级提升持续更新中,up!up!up!!欢迎点赞&&收藏&&订阅。

@TOC

✨ 前言

在 Java 应用中,定时任务是一个非常常见的需求。Spring 提供了 @Scheduled 注解用于配置静态的定时任务,但某些场景下,我们需要动态地添加或移除定时任务,例如基于用户的配置、动态时间间隔调整等。本文将深入解析如何在 Spring 项目中动态添加 Scheduled 定时任务,并通过代码示例帮助你快速掌握。


📌 定时任务的基础:@Scheduled

在 Spring 中,@Scheduled 注解用于定义定时任务。它支持多种触发方式:

  1. fixedRate:固定频率触发。
  2. fixedDelay:固定延迟触发。
  3. cron:基于 Cron 表达式触发。

示例:静态定时任务

@Component
public class StaticScheduledTask {

    @Scheduled(fixedRate = 5000) // 每 5 秒触发一次
    public void runTask() {
        System.out.println("Executing static scheduled task...");
    }
}

虽然 @Scheduled 很方便,但它是静态的,无法在运行时动态添加或移除任务。因此,接下来我们介绍如何动态添加定时任务。


📌 动态添加定时任务的实现

Spring 的 TaskScheduler 接口提供了动态管理定时任务的能力。通过实现 TaskScheduler,我们可以在运行时添加、移除和管理任务。

1. 使用 ThreadPoolTaskScheduler 动态管理定时任务

1.1 配置 TaskScheduler

Spring 提供了 ThreadPoolTaskScheduler,这是一个线程池定时任务调度器。

配置类:

@Configuration
public class TaskSchedulerConfig {

    @Bean
    public ThreadPoolTaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(10); // 设置线程池大小
        scheduler.setThreadNamePrefix("DynamicTask-");
        return scheduler;
    }
}

1.2 动态添加定时任务

通过 TaskScheduler 提供的方法,可以在运行时动态添加定时任务。

示例代码:

@Service
public class DynamicTaskService {

    @Autowired
    private TaskScheduler taskScheduler;

    private ScheduledFuture<?> scheduledTask;

    // 动态添加定时任务
    public void addTask(Runnable task, long interval) {
        if (scheduledTask != null) {
            scheduledTask.cancel(true); // 如果已有任务,先取消
        }
        scheduledTask = taskScheduler.scheduleAtFixedRate(task, interval); // 添加新任务
    }

    // 动态移除定时任务
    public void removeTask() {
        if (scheduledTask != null) {
            scheduledTask.cancel(true);
            scheduledTask = null;
        }
    }
}

调用示例:

@RestController
@RequestMapping("/tasks")
public class TaskController {

    @Autowired
    private DynamicTaskService taskService;

    @PostMapping("/start")
    public String startTask(@RequestParam long interval) {
        taskService.addTask(() -> System.out.println("Executing dynamic task..."), interval);
        return "Task started with interval: " + interval + "ms";
    }

    @PostMapping("/stop")
    public String stopTask() {
        taskService.removeTask();
        return "Task stopped.";
    }
}

📌 基于 Cron 表达式的动态任务

除了固定间隔的定时任务,还可以基于 Cron 表达式 添加动态任务。

2.1 动态添加 Cron 表达式任务

Spring 的 CronTrigger 可以帮助我们动态创建基于 Cron 表达式的任务。

示例代码:

@Service
public class CronTaskService {

    @Autowired
    private TaskScheduler taskScheduler;

    private ScheduledFuture<?> cronTask;

    // 动态添加 Cron 表达式任务
    public void addCronTask(Runnable task, String cronExpression) {
        if (cronTask != null) {
            cronTask.cancel(true); // 如果已有任务,先取消
        }
        CronTrigger cronTrigger = new CronTrigger(cronExpression); // 创建 CronTrigger
        cronTask = taskScheduler.schedule(task, cronTrigger); // 添加任务
    }

    // 移除 Cron 表达式任务
    public void removeCronTask() {
        if (cronTask != null) {
            cronTask.cancel(true);
            cronTask = null;
        }
    }
}
2.2 调用示例

Controller 示例:

@RestController
@RequestMapping("/cron-tasks")
public class CronTaskController {

    @Autowired
    private CronTaskService cronTaskService;

    @PostMapping("/start")
    public String startCronTask(@RequestParam String cronExpression) {
        cronTaskService.addCronTask(() -> System.out.println("Executing dynamic cron task..."), cronExpression);
        return "Cron task started with expression: " + cronExpression;
    }

    @PostMapping("/stop")
    public String stopCronTask() {
        cronTaskService.removeCronTask();
        return "Cron task stopped.";
    }
}

启动示例:

  • 请求:POST /cron-tasks/start
  • 参数:cronExpression = "0/5 * * * * *" (每 5 秒执行一次)

停止示例:

  • 请求:POST /cron-tasks/stop

📌 多任务的动态管理

在实际场景中,我们可能需要动态管理多个定时任务。这可以通过维护一个任务列表来实现。

3.1 多任务管理示例

Service 实现:

@Service
public class MultiTaskService {

    @Autowired
    private TaskScheduler taskScheduler;

    private Map<String, ScheduledFuture<?>> tasks = new ConcurrentHashMap<>();

    // 添加任务
    public void addTask(String taskId, Runnable task, String cronExpression) {
        if (tasks.containsKey(taskId)) {
            tasks.get(taskId).cancel(true); // 如果任务已存在,先取消
        }
        CronTrigger cronTrigger = new CronTrigger(cronExpression);
        ScheduledFuture<?> future = taskScheduler.schedule(task, cronTrigger);
        tasks.put(taskId, future);
    }

    // 移除任务
    public void removeTask(String taskId) {
        if (tasks.containsKey(taskId)) {
            tasks.get(taskId).cancel(true);
            tasks.remove(taskId);
        }
    }

    // 查看任务
    public Set<String> listTasks() {
        return tasks.keySet();
    }
}

Controller 示例:

@RestController
@RequestMapping("/multi-tasks")
public class MultiTaskController {

    @Autowired
    private MultiTaskService multiTaskService;

    @PostMapping("/add")
    public String addTask(@RequestParam String taskId, @RequestParam String cronExpression) {
        multiTaskService.addTask(taskId, () -> System.out.println("Task " + taskId + " is running..."), cronExpression);
        return "Task added with ID: " + taskId;
    }

    @PostMapping("/remove")
    public String removeTask(@RequestParam String taskId) {
        multiTaskService.removeTask(taskId);
        return "Task removed with ID: " + taskId;
    }

    @GetMapping("/list")
    public Set<String> listTasks() {
        return multiTaskService.listTasks();
    }
}

📌 动态定时任务的注意事项

  1. 线程池管理

    • 确保线程池的大小足够,避免任务因线程耗尽而无法执行。
    • 使用 ThreadPoolTaskScheduler 配置合理的线程池。
  2. 任务冲突

    • 在动态添加任务时,应避免任务 ID 冲突,建议使用唯一标识符。
  3. Cron 表达式校验

    • 添加任务前,校验 Cron 表达式是否合法。
  4. 任务清理

    • 在移除任务时,一定要调用 cancel(true) 以释放资源。

🔮 未来展望

  1. 支持动态优先级

    • 动态调整任务的优先级,保证高优任务优先执行。
  2. 任务状态监控

    • 集成监控工具(如 Prometheus、Grafana)实时查看任务执行状态。
  3. 持久化任务配置

    • 将动态任务配置存储到数据库中,支持重启后自动加载。

✨ 总结

通过 Spring 提供的 TaskScheduler,我们可以非常方便地动态添加和管理定时任务,从而满足动态化、多任务管理的业务需求。在实际开发中,通过结合 Cron 表达式、多任务管理等技术,可以实现更加灵活的调度系统。

希望本文能帮助你更好地理解和实践动态定时任务的实现。如果你有更多问题或建议,欢迎交流!😊

🧧福利赠与你🧧

  无论你是计算机专业的学生,还是对编程有兴趣的小伙伴,都建议直接毫无顾忌的学习此专栏「滚雪球学SpringBoot」,bug菌郑重承诺,凡是学习此专栏的同学,均能获取到所需的知识和技能,全网最快速入门SpringBoot,就像滚雪球一样,越滚越大, 无边无际,指数级提升。

最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。

同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板、技术文章Markdown文档等海量资料。

✨️ Who am I?

我是bug菌,CSDN | 掘金 | InfoQ | 51CTO | 华为云 | 阿里云 | 腾讯云 等社区博客专家,C站博客之星Top30,华为云2023年度十佳博主,掘金多年度人气作者Top40,掘金等各大社区平台签约作者,51CTO年度博主Top12,掘金/InfoQ/51CTO等社区优质创作者;全网粉丝合计 30w+;更多精彩福利点击这里;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试真题、4000G PDF电子书籍、简历模板等海量资料,你想要的我都有,关键是你不来拿。

-End-

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。