我们提供安全,免费的手游软件下载!

安卓手机游戏下载_安卓手机软件下载_安卓手机应用免费下载-先锋下载

当前位置: 主页 > 软件教程 > 软件教程

SpringBoot实现轻量级动态定时任务管控及组件化

来源:网络 更新时间:2024-11-23 09:31:24

关于动态定时任务

关于在SpringBoot中使用定时任务,大部分都是直接使用SpringBoot的 @Scheduled 注解,如下:

或者或者使用第三方的工具,例如XXL-Job等。就XXL-Job而言,如果说是大型项目,硬件资源和项目环境都具备,XXL-Job确实是最佳的选择,可是对于项目体量不大,又不想过多的引入插件;使用XXL-Job多少有点“杀鸡用牛刀”的意思;

之所以这样说,是因为在SpringBoot中集成使用XXL-Job的步骤如下:

  1. 引入依赖,配置执行器Bean
  2. 在自己项目中编写定时任务代码
  3. 部署XXL-Job
  4. 登录XXL-Job调度中心的 Web 控制台,创建一个新的任务,选择刚才配置的执行器和任务处理器,设置好触发条件(如 Cron 表达式)和其他选项后保存
  5. 生产环境下,还要把配置好任务的XXL-Job和项目一起打包

这一套步骤在中小型项目中,明显成本大于效果,而使用XXL-Job无非就是想动态的去管理定时任务,可以在运行状态下随意的执行、中断、调整执行周期、查看运行结果,而不是像基于 @Scheduled 注解实现后,无法改变。

所以,这里就基于SpringBoot实现动态调度定时任务,之前针对这个问题,我写过一篇CSDN文章(连接放在下方),最近博主将相关的代码进行了汇总,并且在易用性和扩展性上进行了加强,基于COLA架构理论,封装到了组件层

这次加强主要包括:

  1. 剥离了任务的持久化,使其依赖更简洁,真正以starter的形式开箱即用
  2. 扩展了方法级的定时任务注册,能够像xxl-job一样,一个注解搞定动态定时任务的注册及管理

动态定时任务实现思路

关于动态定时任务的核心思路是 反射+定时任务模板 ,这两部分的核心框架不变,相关内容可以回顾我之前的博客:

轻量级动态定时任务调度

这里主要是针对强化的第二点进行思路解释,第二点的强化是加入了类扫描机制,通过扫描,实现了自动注册,规避了之前每新增一个定时任务都必须得预制SQL的步骤:

类级别定时任务实现思路 :在原模板模式的基础下,基于AbstractBaseCronTask类自定义的定时任务子类作为类级别定时任务,即一个类为一个定时任务,初始时由包扫描所有的子类,并使用反射将其实例化,逐一加入到进程管理中,并激活定时调度。

基于@MethodJob的方法级别任务实现思路 :以 AbstractBaseCronTask类为基础,定义一个固定的子类BaseMethodLevelTask 并在其内部限定任务的执行方式 扫描所有标注了@MethodJob的方法及其所属的Bean,连同Bean及方法的反射类作为构造函数,生成BaseMethodLevelTask对象 因为BaseMethodLevelTask也是AbstractBaseCronTask的子类,则可以以类级别定时任务的方式,将其生成定时任务,并进行管理。

本质还是管理的AbstractBaseCronTask子类在线程池中的具体对象,不同的地方是类级别定时任务是一个具体的任务类仅生成一个对象,class路径即是唯一的标识,而方法级别的定时任务均基于BaseMethodLevelTask生成无数个对象,具体标识则是构造函数传入的Bean的反射对象和方法名。

对此部分感兴趣的可以一起参与开发,该项目地址: Gitee源码 ,主要为其中 task-component 模块。

组件使用方法

根据Git地址,将源码down下,编译安装到本地私仓中,以Maven的形式引入即可,该组件遵循Spring-starter规范,开箱即用。

Yaml配置说明

给出一个yaml模板:

对于task-component的配置只有两个, task-class-package data-file-path

属性 说明 是否必须 缺省值
task-class-package

指定定时任务存放的包路径,不填写或无此属性则默认全项目扫描,填写后可有效减少初始化时间

*
data-file-path

定时任务管理的数据存放文件及其路径,默认不填写则存放项目运行目录下,如自行扩展实现,则该配置自动失效

class:db/task_info.json

此处的两个配置项都包含默认值,所以不进行yml的 gcc-task 仍旧可以使用该组件

新建定时任务

对于该组件在进行定时任务的创建时,有两种,分别是类级定时任务和方法级定时任务,两者的区别在于是以类为基本的单位还是以方法为一个定时任务的单位,对于运行效果则并无区别,根据个人喜好,选择使用哪一种即可

类级定时任务

新增一个定时任务逻辑,则需要实现基类 AbstractBaseCronTask ,并加入注解 @ClassJob

ClassJob的参数如下

参数 说明 样例
cron 定时任务默认的执行周期,仅在首次初始化该任务使用( 必填 10 0/2 * * * ?
desc 任务描述,非必填 这是测试任务
bootup 是否开机自启动, 缺省值为 false false

cron 属性仅在第一次新增该任务时提供一个默认的执行周期,必须填写,后续任务加载后,定时任务相关数据会被存放在文件或数据库中,此时则以文件或数据库中该任务的cron为主,代码中的注解则不会生效,如果想重置,则删除已经持久化的任务即可。

一个完整的Demo如下:

继承 AbstractBaseCronTask 必须要实现携带TaskEntity参数的 构造函数 beforeJob() startJob() afterJob() 三个方法即可。 原则上这三个方法是规范定时任务的执行,实际使用,只需要把核心逻辑放在三个方法中任何一个即可

因定时任务类是非SpringBean管理的类,所以 在自定义的定时任务类内无法使用任何Spring相关的注解(如@Autowired) 但是却可以通过自带的 getServer(Class className) 方法来获取任何Spring上下文中的Bean

例如,你有一个UserService的接口及其Impl的实现类,想在定时任务类中使用该Bean,则可以:

方法级定时任务

如果不想新建类,或者不想受限于 AbstractBaseCronTask 的束缚 ,则可以像xxl-job定义定时任务一样,直接在某个方法上标注@MethodJob注解即可。

@MethodJob的参数如下:

参数 说明 样例
cron 定时任务默认的执行周期,仅在首次初始化该任务使用( 必填 10 0/2 * * * ?
desc 任务描述,非必填 这是测试任务
bootup 是否开机自启动, 缺省值为 false false

通ClassJob一样,cron 属性仅在第一次新增该任务时提供一个默认的执行周期,必须填写,后续任务加载后,定时任务相关数据会被存放在文件或数据库中,此时则以文件或数据库中该任务的cron为主,代码中的注解则不会生效,如果想重置,则删除已经持久化的任务即可。

下面是一个例子:

注:该注解仅支持SpringBoot中标注为 @Component @Service @Repository 的Bean

动态调度任务接口说明

定时任务相关的管理操作均封装在 TaskScheduleManagerService 接口中,接口内容如下:

可直接在外部项目中注入使用即可:

接口效果:

可使用该接口,进行UI页面开发。

关于任务持久化的扩展

在实现思路中提到过,task-component的执行原理需要将注册后的任务持久化,下次再启动项目时,则直接使用持久化的TaskEntity来加载定时任务。

考虑到定时任务的数量不大,且对于交互要求不高,另外考虑封装成组件的 独立性 普适性 ,不想额外引入数据库依赖和ORM框架,所以组件默认的是以JSON文件的形式进行存储,实际使用中,考虑到便利性,可以自行对持久化部分进行扩展。

所谓持久化,其实本制是持久化TaskEntity对象,TaskEntity对象如下:

扩展的主要操作为两步:

  1. 新建存放taskEntity的表
  2. 实现TaskRepository接口

首先新建数据库表,这里以Mysql为例给出建表语句:

实现 TaskEntityRepository 接口,接口内容为:

只需要新建类,然后实现该接口即可,如下是基于Mybatis-Plus进行的实现样例:

至此,项目中则可以以数据库表的形式来管理定时任务:

任务运行日志: