前言
本文是自定义任务调度中心项目的其中一部分内容,单独整理为一篇博客分享给大家,相比于目前的主流任务调度中间件XXL-JOB,主要做了以下一些调整:
- 生成的任务支持预设优先级。
- 不支持预设优先级的劣势:当两个任务同时产生,并交由同一执行器时,其调度顺序仅由通知先后决定,而无法主动的预设优先级。这使得我们无法在同一时刻将两个具有依赖关系的任务交由同一执行器,而是只能预设提前量(而预设的提前量可能由于网络波动而出现差错)
- 任务注册支持一次性任务的注册
我们会从最简单的中心化任务调度开始,一步步扩展我们的项目功能,感兴趣的可移步我的另一篇博客:从简单到复杂的自研任务调度中间件记录
参考
本文思路参考自spring boot实现动态增删启停定时任务,详细内容容后补充
- 疑问1:为什么要用ScheduledFuture类?
- 解答:因为SpringTask类的schedule方法返回的是ScheduledFuture类型,代表这个任务会在未来某个时间执行并返回结果
实现逻辑
- 第一步:覆写TaskScheduler类,添加线程池的支持
- 目的1:TaskScheduler类是SpringTask所提供的进行定时任务调度的接口类,若是想执行一个定时任务,只需要通过TaskScheduler类的schedule方法
- 细节1:schedule方法的常规传参为Runnable类+Trigger类,Trigger可通过Cron语句控制频率,Runnable控制定时任务执行细节
- 目的2:TaskScheduler类默认只能允许一个线程执行定时任务,因此为同时启动多个定时任务,我们需要引入线程池的支持
- 第二步:实现Runnable类,实现的类支持传入beanName, methodName以及params
- 目的:构建一个定时任务执行框架,该框架支持调取对应的beanName(从Spring容器中取出,之所以这么设计主要是适应于JAVA开发时,大多数方法均由bean类注入调用),并通过反射执行其中的无参或带参方法,可扩展性更强
- 细节:在设计时,我们认为同一个beanName,同一个methodName以及同一个params对应的应该是同一个Runnable类。这个细节是可讨论可更正的,我们这么设计的目的是便于通过上述三个参数唯一确定一个Runnable类,因此我们重写了该类的equals和hashCode方法,使其唯一依赖于上述三个参数。如果你认为你需要更多的参数来唯一确定一个Runnable,不妨在此处扩展你的需求
- 第三步:实现TaskScheduler异步执行的管理类ScheduledTask
- 目的:由于TaskScheduler是通过异步执行机理,在发起schedule后,会返回ScheduledFuture类,可对该异步执行添加管理类,主要是增加取消异步执行的功能
- 第四步:实现动态定时任务增删改查管理类
- 目的:与第三步不同,这里实现的是整个动态定时任务组的管理,而非其中某个定时任务的管理,是更高一层的整合(当然,其完全依赖于前三步所构建的单一定时任务的实现细节)
- 细节:我们通过ConcurrentHashMap来管理整个动态定时任务组,其中key为Runnable,value为ScheduledTask。
- 这里以增加一个定时任务为例:要增加一个定时任务,首先需要新建一个以beanName,methodName,params组成的Runnable,然后调用TaskScheduler的schedule方法并获取其返回值,将返回值交由ScheduledTask管理后,我们将这一对(key, value)组合压入HashMap
- 这里以停止一个定时任务为例,来分析我们之前准备工作的必要性:要停止一个定时任务,首先需要新建一个以同样beanName,methodName,params组成的Runnable,该参数作为key可唯一定位之前的定时任务在HashMap中的位置(hashCode一致且equals为True)。取出ScheduledTask后,调用其cacel方法,即可停止一个异步的任务
代码
这里我就不搬运了,可以直接去原址拿spring boot实现动态增删启停定时任务
本文链接:https://my.lmcjl.com/post/2576.html
展开阅读全文
4 评论