从零搭建开发脚手架 基于Spring Task实现动态管理任务

开发 后端
Timer 是 Jdk自带的定时任务执行类,无论任何项目都可以直接使用 Timer 来实现定时任务,所以 Timer 的优点就是使用方便。

[[396614]]

本文转载自微信公众号「Java大厂面试官」,作者laker。转载本文请联系Java大厂面试官公众号。

什么是定时任务

定时任务是指调度程序在指定的时间或周期触发执行的任务,常用场景如下:

  • 定时发短信
  • 定时变更数据
  • 定时统计数据
  • 定时修改状态
  • 定时开始活动等

常见几种JAVA实现方式

Timer

简介:Timer 是 Jdk自带的定时任务执行类,无论任何项目都可以直接使用 Timer 来实现定时任务,所以 Timer 的优点就是使用方便。

原理:

  • 调度器:单线程。
  • 任务存储:最小堆实现任务存储。

优点:Jdk自带类,无需引入其他Jar,简单易用。

缺点:Timer中的多个任务只能使用一个线程去执行,因此任务之间的执行情况会相互影响。

  • 当一个任务的执行时间过长时,会影响其他任务的调度任务异常影响其他任务。
  • 当一个任务抛出异常,其他任务也会终止运行.

结论:基本无人使用。

ScheduledExecutorService

简介:ScheduledExecutorService 是JDK里面自定义的几种线程池中的一种,支持多线程并发的去执行多个调度任务,弥补了Timer的缺陷。

原理:

  • 调度器:多线程。
  • 任务存储:最小堆实现任务存储。

优点:Timer能做到的事情ScheduledExecutorService都能做到,且完美的解决上面所说的Timer存在的两个问题。

缺点:只支持固定速率(fixed-rate)或固定延迟(fixed-delay)的调度任务,不灵活。

结论:常用于框架内部定时任务。

Spring Task

描述:Spring Framework 自带的定时任务。

优点:同ScheduledExecutorService,同时增加了支持cron表达式,可以配置任意基于时钟的调度任务。

缺点:

  • 不支持动态修改任务状态、暂停/恢复任务,以及终止运行中任务。
  • 不支持在线监控执行的任务。

原理:ScheduledExecutorService的扩展。

结论:常用于中小型企业,作为单机定时任务使用。

以上都是单机版本。

其他分布式定时任务诸如:quartz、xxl-job、elastic-job等等,功能、性能都很强劲,这里不作为研究对象,详情参考:

  • Java定时任务框架对比
  • 定时任务实现原理 最小堆 时间轮

上面的这些框架都不是我想选择的,要想自由的掌控雷电,那就自己造个简易轮子,满足90%需求即可。

期望实现如下特性:

  • 轻量、轻量、轻量。
  • 支持在线监控执行的任务。
  • 支持动态修改任务状态、暂停/恢复任务,以及终止运行中任务。
  • 支持在线配置调度任务入参和。
  • 支持集群环境扩展(可选)。

收集了半天信息,直接使用Spring Task就可以实现,仅依赖Spring Boot。

Spring Task详解

初级静态配置任务

代码示例:

  1. @Component  
  2. @EnableScheduling // 开启定时任务 
  3. public class DemoApplication { 
  4.  // 添加定时任务 
  5.     @Scheduled(cron = "0/5 * * * * *") // cron 表达式,每5秒执行 
  6.     public void doTask(){ 
  7.         System.out.println("我是定时任务~"); 
  8.     } 

无法动态修改任务状态、暂停/恢复任务,以及终止运行中任务。

进阶动态配置任务

实现设计

关键技术点和坑

  • Spring Task的调度器默认是线程数为1的ThreadPoolTaskScheduler,自动装配类为TaskSchedulingAutoConfiguration,多任务之间的执行会相互影响,一定要修改默认值。
  • 通过TaskScheduler接口,可以扩展实现动态修改任务状态、暂停/恢复任务,以及终止运行中任务。
    • TaskScheuler是在Spring 3.0中引入的,有多种方法可以在将来的某个时刻运行,它还返回ScheduledFuture接口的对象,可用于取消计划的任务或检查任务是否完成。
  • cron-utils一个Java库,用于解析,验证Cron表达式,可以去GitHub查看详细说明。

实现设计

定义IJob接口,用于客户端描述任务

  1. public interface IJob { 
  2.     void execute(JobContext map) throws JobException; 

定义注解,用于配合IJob接口定义任务

  1. @Target({ElementType.TYPE}) 
  2. @Retention(RetentionPolicy.RUNTIME) 
  3. @Documented 
  4. @Component 
  5. public @interface Job { 
  6.  
  7.     @AliasFor(annotation = Component.class) 
  8.     String value() default ""
  9.  
  10.     /** 
  11.      * cron 表达式默认不"-"代表不执行 
  12.      */ 
  13.     String cron() default "-"
  14.  
  15.     /** 
  16.      * 任务编码 必须唯一 
  17.      */ 
  18.     String taskCode(); 
  19.  
  20.     /** 
  21.      * 任务名称 
  22.      */ 
  23.     String taskName(); 
  24.  

定义运行任务状态

  1. public class Task{ 
  2.     /** 
  3.      * 任务的编码 必须全局唯一 
  4.      */ 
  5.     private String taskCode; 
  6.     /** 
  7.      * 任务的名称 
  8.      */ 
  9.     private String taskName; 
  10.     /** 
  11.      * 任务的类名称 
  12.      */ 
  13.     private String taskClassName; 
  14.     /** 
  15.      * 任务的cron表达式 
  16.      */ 
  17.     private String taskCron; 
  18.  
  19.     @JsonIgnore 
  20.     private ScheduledFuture scheduledFuture; 
  21.  
  22.     @JsonIgnore 
  23.     private IJob job; 
  24.  
  25.     private TaskStateEnum taskState; 

定义任务存储接口,用于存储在缓存或者DB中

  1. public interface ITaskStore { 
  2.  
  3.     void saveTask(Task task); 
  4.  
  5.     List<Task> list(); 
  6.  
  7.     Task updateTaskByTaskCode(String taskCron, String taskName, String taskCode); 
  8.  
  9.     Task updateTaskStateByTaskCode(TaskStateEnum taskState, String taskCode); 
  10.  
  11.     void deleteTaskByTaskCode(String taskCode); 
  12.  
  13.     Task findByTaskCode(String taskCode); 
  14.  

定义任务锁接口,解决并发问题,以及扩展支持集群环境

  1. public interface ILockService { 
  2.     void lock(String taskCode); 
  3.     void unlock(String taskCode); 
  4. }     

定义事件监听器,用于监听任务的状态事件,可扩展状态监控,各种回调等

  1. public interface IEventListener { 
  2.     void listener(Event event); 

核心处理器,处理核心流程

  • 初始化加载所有IJob的实现 从Spring容器获取IJob实现类并解析Job注解
  • 添加任务threadPoolTaskScheduler.schedule(task,cron)
  • 更新任务详情
    • scheduledFuture.cancel(true)
    • threadPoolTaskScheduler.schedule(task,cron)
  • 启动任务 threadPoolTaskScheduler.schedule(task,cron)
  • 暂停任务 scheduledFuture.cancel(true)
  • 任务监控 TaskList

待实现功能

  • 重试补偿:失败重试。
  • failstore : 存储失败任务,供人肉补偿。
  • misfire:存储错过的任务,供人肉补偿。

自己在核心处理器中加下相应的增强功能逻辑即可。

使用示例

直接实现IJob接口并加上Job注解即可

  1. @Job(taskCode = "job1", taskName = "laker测试任务",cron = "0/5 * * * * *"
  2. @Slf4j 
  3. public class TestJob implements IJob { 
  4.     @Override 
  5.     public void execute(Map map) throws Exception { 
  6.         log.info("laker job run"); 
  7.         TimeUnit.SECONDS.sleep(10); 
  8.     } 

全部代码:https://gitee.com/lakernote/lakernote

参考:https://juejin.cn/post/6844904002606350343

SpringBoot官网

 

责任编辑:武晓燕 来源: Java大厂面试官
相关推荐

2021-09-01 10:07:43

开发零搭建Groovy

2021-03-09 17:11:09

数据库脚手架开发

2020-08-19 08:55:47

Redis缓存数据库

2021-07-13 18:42:38

Spring Boot脚手架开发

2021-05-13 17:02:38

MDC脚手架日志

2021-04-13 14:47:53

认证授权Java

2021-07-29 18:49:49

Spring开发脚手架

2021-04-20 19:24:16

脚手架 Java微信

2021-03-11 14:16:47

Spring Boo开发脚手架

2021-06-02 17:58:49

脚手架 幂等性前端

2021-02-19 22:43:50

开发脚手架Controller

2016-08-10 14:59:41

前端Javascript工具

2020-06-29 11:35:02

Spring BootJava脚手架

2023-11-21 17:36:04

OpenFeignSentinel

2014-08-15 09:36:06

2021-01-07 05:34:07

脚手架JDK缓存

2021-08-30 06:59:06

StrviewAppStrview.js项目

2022-07-11 10:38:06

TienChin项目动态

2021-05-21 05:22:52

脚手架工具项目

2018-06-11 14:39:57

前端脚手架工具node.js
点赞
收藏

51CTO技术栈公众号