基于quartz实现定时任务管理系统
背景
说起定时任务框架,首先想到的是Quartz。这是定时任务的老牌框架了,它的优缺点都很明显。借助PowerJob 的readme文档的内容简单带过一下这部分。
除了上面提到,还有elastic-job-lite
、quartzui
也是相当火热的,可以自行了解一下。
那么都这么多后起之秀,个个吊打quartz,为什么我还选择用quartz来做定时任务?技术是服务于业务的,肯定是有需求呗。公司有个统一管理平台,现在需要开发一个定时任务管理平台,可以动态去管理配置定时任务、查看运行日志。
为什么不考虑其它的框架?由于需求要定制化ui界面和定时任务执行结果接入统一的通知中心等等需求,上面大多数框架都是通过简单配置开箱即用,定制化需要对源码有一定熟悉程度,而quartz我在大学就用了很多次了,非常熟悉,改造相对容易。
需求分析
- 定时任务的增删改查
- 定时任务执行日志查看
详细设计
开发环境
jdk 1.8
spring boot 2.7.7
quartz 单机版
Mysql 8.0
1. 定时任务的实现
quartz的任务实际是通过内置Java类实现job
接口或者继承QuartzJobBean
实现executeInternal来实现定时任务的添加。所以我们在管理页面上所做的增删改查操作都不可能是真正意义上地去修改了任务类,而是修改了映射类。举个例子来说,比如Power Job的管理界面
我们修改的这些任务名称、定时信息的持久化操作都不会是操作了真正的任务类,而是修改了一个绑定这个任务类的映射类。如下图中的类就是任务类
而图片中的这些就是属性就是映射类的属性。
你可以先是觉得任务类和映射类之间是一对一的关系,映射类记录了定时任务的执行频率(cron)、名称、任务类完整类名等其它的信息,然后在执行过程中通过完整类名反射获得任务类,任务类再根据这些信息去执行。
但如果每个定时任务,我们都要去实现Job接口创建一个类,相同的那些代码比如获取trigger、scheduler等等,都要出现在每个类中,每次添加一个定时任务都要多一个专门的定时任务类。每次开发时都要关注业务和定时任务类之间的关系,多了之后是有点烦。
我推荐的做法是,创建一个具备http请求功能的任务类,将业务操作开发成一个接口,在配置映射类时,将http链接配置上去,这样一到时间 ,就会请求到对应的业务接口。这样使得后续的定时任务功能开发更专注于业务开发,方便使用。尤其是团队开发中,对一些不熟悉quartz的朋友格外友好。
编码实现
引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.11</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
映射实体类
@TableName
@Data
public class ScheduleJob {
@TableId
private Long id;
@TableField
private String jobName;
@TableField
private String cronExpr; // cron表达式
@TableField
private String jobStatus; // 任务状态
@TableField
private String url; // 业务接口
}
必不可少的属性大概就是上面这几个,后续需要再添加
service层与mapper层我偷个懒,直接用mybatisplus的api
ScheduleJobService
@Service
public class ScheduleJobService extends ServiceImpl<ScheduleJobMapper, ScheduleJob> {
}
ScheduleJobMapper
@Mapper
public interface ScheduleJobMapper extends BaseMapper<ScheduleJob> {
}
有了这些就可以先做个添加定时任务的接口测试一下流程是否通畅
ScheduleJobController
@RestController
public class ScheduleJobController {
@Resource
private ScheduleJobService scheduleJobService;
@PostMapping("/scheduleJob"