经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring » 查看文章
SpringBoot?实现动态添加定时任务功能
来源:jb51  时间:2022/2/28 13:24:02  对本文有异议

最近的需求有一个自动发布的功能, 需要做到每次提交都要动态的添加一个定时任务

代码结构

1. 配置类

  1. package com.orion.ops.config;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.scheduling.TaskScheduler;
  5. import org.springframework.scheduling.annotation.EnableScheduling;
  6. import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
  7. /**
  8. * 调度器配置
  9. *
  10. * @author Jiahang Li
  11. * @version 1.0.0
  12. * @since 2022/2/14 9:51
  13. */
  14. @EnableScheduling
  15. @Configuration
  16. public class SchedulerConfig {
  17. @Bean
  18. public TaskScheduler taskScheduler() {
  19. ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
  20. scheduler.setPoolSize(4);
  21. scheduler.setRemoveOnCancelPolicy(true);
  22. scheduler.setThreadNamePrefix("scheduling-task-");
  23. return scheduler;
  24. }
  25. }

2. 定时任务类型枚举

  1. package com.orion.ops.handler.scheduler;
  2. import com.orion.ops.consts.Const;
  3. import com.orion.ops.handler.scheduler.impl.ReleaseTaskImpl;
  4. import com.orion.ops.handler.scheduler.impl.SchedulerTaskImpl;
  5. import lombok.AllArgsConstructor;
  6. import java.util.function.Function;
  7. /**
  8. * 任务类型
  9. *
  10. * @author Jiahang Li
  11. * @version 1.0.0
  12. * @since 2022/2/14 10:16
  13. */
  14. @AllArgsConstructor
  15. public enum TaskType {
  16. /**
  17. * 发布任务
  18. */
  19. RELEASE(id -> new ReleaseTaskImpl((Long) id)) {
  20. @Override
  21. public String getKey(Object params) {
  22. return Const.RELEASE + "-" + params;
  23. }
  24. },
  25. * 调度任务
  26. SCHEDULER_TASK(id -> new SchedulerTaskImpl((Long) id)) {
  27. return Const.TASK + "-" + params;
  28. ;
  29. private final Function<Object, Runnable> factory;
  30. * 创建任务
  31. *
  32. * @param params params
  33. * @return task
  34. public Runnable create(Object params) {
  35. return factory.apply(params);
  36. }
  37. * 获取 key
  38. * @return key
  39. public abstract String getKey(Object params);
  40. }

这个枚举的作用是生成定时任务的 runnable 和 定时任务的唯一值, 方便后续维护

3. 实际执行任务实现类

  1. package com.orion.ops.handler.scheduler.impl;
  2. import com.orion.ops.service.api.ApplicationReleaseService;
  3. import com.orion.spring.SpringHolder;
  4. import lombok.extern.slf4j.Slf4j;
  5. /**
  6. * 发布任务实现
  7. *
  8. * @author Jiahang Li
  9. * @version 1.0.0
  10. * @since 2022/2/14 10:25
  11. */
  12. @Slf4j
  13. public class ReleaseTaskImpl implements Runnable {
  14. protected static ApplicationReleaseService applicationReleaseService = SpringHolder.getBean(ApplicationReleaseService.class);
  15. private Long releaseId;
  16. public ReleaseTaskImpl(Long releaseId) {
  17. this.releaseId = releaseId;
  18. }
  19. @Override
  20. public void run() {
  21. log.info("定时执行发布任务-触发 releaseId: {}", releaseId);
  22. applicationReleaseService.runnableAppRelease(releaseId, true);
  23. }

4. 定时任务包装器

  1. package com.orion.ops.handler.scheduler;
  2. import org.springframework.scheduling.TaskScheduler;
  3. import org.springframework.scheduling.Trigger;
  4. import java.util.Date;
  5. import java.util.concurrent.ScheduledFuture;
  6. /**
  7. * 定时 任务包装器
  8. *
  9. * @author Jiahang Li
  10. * @version 1.0.0
  11. * @since 2022/2/14 10:34
  12. */
  13. public class TimedTask {
  14. /**
  15. * 任务
  16. */
  17. private Runnable runnable;
  18. * 异步执行
  19. private volatile ScheduledFuture<?> future;
  20. public TimedTask(Runnable runnable) {
  21. this.runnable = runnable;
  22. }
  23. * 提交任务 一次性
  24. *
  25. * @param scheduler scheduler
  26. * @param time time
  27. public void submit(TaskScheduler scheduler, Date time) {
  28. this.future = scheduler.schedule(runnable, time);
  29. * 提交任务 cron表达式
  30. * @param trigger trigger
  31. public void submit(TaskScheduler scheduler, Trigger trigger) {
  32. this.future = scheduler.schedule(runnable, trigger);
  33. * 取消定时任务
  34. public void cancel() {
  35. if (future != null) {
  36. future.cancel(true);
  37. }
  38. }

这个类的作用是包装实际执行任务, 以及提供调度器的执行方法

5. 任务注册器 (核心)

  1. package com.orion.ops.handler.scheduler;
  2. import com.orion.ops.consts.MessageConst;
  3. import com.orion.utils.Exceptions;
  4. import com.orion.utils.collect.Maps;
  5. import org.springframework.beans.factory.DisposableBean;
  6. import org.springframework.beans.factory.annotation.Qualifier;
  7. import org.springframework.scheduling.TaskScheduler;
  8. import org.springframework.scheduling.support.CronTrigger;
  9. import org.springframework.stereotype.Component;
  10. import javax.annotation.Resource;
  11. import java.util.Date;
  12. import java.util.Map;
  13. /**
  14. * 任务注册器
  15. *
  16. * @author Jiahang Li
  17. * @version 1.0.0
  18. * @since 2022/2/14 10:46
  19. */
  20. @Component
  21. public class TaskRegister implements DisposableBean {
  22. private final Map<String, TimedTask> taskMap = Maps.newCurrentHashMap();
  23. @Resource
  24. @Qualifier("taskScheduler")
  25. private TaskScheduler scheduler;
  26. /**
  27. * 提交任务
  28. *
  29. * @param type type
  30. * @param time time
  31. * @param params params
  32. */
  33. public void submit(TaskType type, Date time, Object params) {
  34. // 获取任务
  35. TimedTask timedTask = this.getTask(type, params);
  36. // 执行任务
  37. timedTask.submit(scheduler, time);
  38. }
  39. * @param cron cron
  40. public void submit(TaskType type, String cron, Object params) {
  41. timedTask.submit(scheduler, new CronTrigger(cron));
  42. * 获取任务
  43. private TimedTask getTask(TaskType type, Object params) {
  44. // 生成任务
  45. Runnable runnable = type.create(params);
  46. String key = type.getKey(params);
  47. // 判断是否存在任务
  48. if (taskMap.containsKey(key)) {
  49. throw Exceptions.init(MessageConst.TASK_PRESENT);
  50. }
  51. TimedTask timedTask = new TimedTask(runnable);
  52. taskMap.put(key, timedTask);
  53. return timedTask;
  54. * 取消任务
  55. public void cancel(TaskType type, Object params) {
  56. TimedTask task = taskMap.get(key);
  57. if (task != null) {
  58. taskMap.remove(key);
  59. task.cancel();
  60. * 是否存在
  61. public boolean has(TaskType type, Object params) {
  62. return taskMap.containsKey(type.getKey(params));
  63. @Override
  64. public void destroy() {
  65. taskMap.values().forEach(TimedTask::cancel);
  66. taskMap.clear();
  67. }

这个类提供了执行, 提交任务的api, 实现 DisposableBean 接口, 便于在bean销毁时将任务一起销毁

6. 使用

  1. @Resource
  2. private TaskRegister taskRegister;
  3. /**
  4. * 提交发布
  5. */
  6. @RequestMapping("/submit")
  7. @EventLog(EventType.SUBMIT_RELEASE)
  8. public Long submitAppRelease(@RequestBody ApplicationReleaseRequest request) {
  9. Valid.notBlank(request.getTitle());
  10. Valid.notNull(request.getAppId());
  11. Valid.notNull(request.getProfileId());
  12. Valid.notNull(request.getBuildId());
  13. Valid.notEmpty(request.getMachineIdList());
  14. TimedReleaseType timedReleaseType = Valid.notNull(TimedReleaseType.of(request.getTimedRelease()));
  15. if (TimedReleaseType.TIMED.equals(timedReleaseType)) {
  16. Date timedReleaseTime = Valid.notNull(request.getTimedReleaseTime());
  17. Valid.isTrue(timedReleaseTime.compareTo(new Date()) > 0, MessageConst.TIMED_GREATER_THAN_NOW);
  18. }
  19. // 提交
  20. Long id = applicationReleaseService.submitAppRelease(request);
  21. // 提交任务
  22. taskRegister.submit(TaskType.RELEASE, request.getTimedReleaseTime(), id);
  23. return id;
  24. }

最后

       这是一个简单的动态添加定时任务的工具, 有很多的改造空间, 比如想持久化可以插入到库中, 定义一个 CommandLineRunner 在启动时将定时任务全部加载, 还可以给任务加钩子自动提交,自动删除等, 代码直接cv一定会报错, 就是一些工具, 常量类会报错, 改改就好了, 本人已亲测可用, 有什么问题可以在评论区沟通

到此这篇关于SpringBoot 实现动态添加定时任务功能的文章就介绍到这了,更多相关SpringBoot 定时任务内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号