定时任务在系统中用到的地方很多,例如每晚凌晨的数据备份,每小时获取第三方平台的 Token 信息等等,之前我们都是在项目中规定这个定时任务什么时候启动,到时间了便会自己启动,那么我们想要停止这个定时任务的时候,就需要去改动代码,还得启停服务器,这是非常不友好的事情
直至遇见 Quartz,利用图形界面可视化管理定时任务,使得我们对定时任务的管理更加方便,快捷
一、Quartz 简介Quartz是一个开源的作业调度框架,它完全由Java写成,并设计用于J2SE和J2EE应用中。它提供了巨大的灵 活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度。它有很多特征,如:数据库支持,集群,插件,EJB作业预构 建,JavaMail及其它,支持cron-like表达式等等。
二、开发前戏1、引入 maven 依赖
<!-- web支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Quartz 定时任务 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
这里引入了 web 的依赖,以及 Quartz 的依赖,其余依赖请根据需求自行引入
2、创建数据表数据模型:
SQL语句:
droptableifexistssys_quartz;
/*==============================================================*/
/* Table: sys_quartz */
/*==============================================================*/
createtablesys_quartz
(
idbigint(20)notnullauto_incrementcomment'主键id',
class_namevarchar(32)comment'任务类名',
cron_expressionvarchar(32)comment'cron表达式',
paramvarchar(32)comment'参数',
descriptvarchar(11)comment'描述',
quartz_statusvarchar(255)comment'启动状态(0--启动1--停止)',
create_time datetimecomment'创建时间',
create_userbigint(20)comment'创建人',
statustinyint(1)default0comment'状态(0--正常1--停用)',
del_flag tinyint(1)default0comment'删除状态(0,正常,1已删除)',
primarykey(id)
)
type=InnoDB;
altertablesys_quartzcomment'定时任务信息表';
importcom.baomidou.mybatisplus.annotation.*;
importcom.baomidou.mybatisplus.extension.activerecord.Model;
importcom.zyxx.common.annotation.Dict;
importio.swagger.annotations.ApiModel;
importio.swagger.annotations.ApiModelProperty;
importlombok.Data;
importlombok.EqualsAndHashCode;
importlombok.experimental.Accessors;
importjava.io.Serializable;
/**
* <p>
* 定时任务信息表
* </p>
*
* @author lizhou
* @since 2020-07-21
*/
@Data
@EqualsAndHashCode(callSuper =false)
@Accessors(chain =true)
@TableName("sys_quartz")
@ApiModel(value="SysQuartz对象", description="定时任务信息表")
publicclassSysQuartzextendsModel<SysQuartz> {
@ApiModelProperty(value ="主键id")
@TableId(value ="id",type= IdType.AUTO)
privateLong id;
@ApiModelProperty(value ="任务类名")
@TableField("class_name")
privateStringclassName;
@ApiModelProperty(value ="cron表达式")
@TableField("cron_expression")
privateStringcronExpression;
@ApiModelProperty(value ="参数")
@TableField("param")
privateStringparam;
@ApiModelProperty(value ="描述")
@TableField("descript")
privateStringdescript;
@ApiModelProperty(value ="启动状态(0--启动1--停止)")
@TableField("quartz_status")
privateInteger quartzStatus;
@ApiModelProperty(value ="状态(0--正常1--停用)")
@TableField("status")
privateInteger status;
@ApiModelProperty(value ="删除状态(0--未删除1--已删除)")
@TableField("del_flag")
@TableLogic
privateInteger delFlag;
@ApiModelProperty(value ="创建者")
@TableField("create_user")
privateLong createUser;
@ApiModelProperty(value ="创建时间")
@TableField("create_time")
privateStringcreateTime;
@Override
protectedSerializable pkVal() {
returnthis.id;
}
}
下面我们就要完成定时任务的 新增、修改、删除、启停 等基本操作了,由于不是很复杂,这里的代码就不贴出来了,贴几张图吧
列表页:
新增页:
四、定时任务1、定时任务类
我们把定时任务都放在 job 包下面,一个定时任务就是一个文件,写一个测试的类 TestJob.java
importcom.zyxx.common.utils.DateUtils;
importlombok.extern.slf4j.Slf4j;
importorg.quartz.Job;
importorg.quartz.JobExecutionContext;
importorg.quartz.JobExecutionException;
/**
* @ClassName TestJob
* 测试定时任务
* @Author Lizhou
* @Date 2020-07-21 10:58:58
**/
@Slf4j
public class TestJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("定时任务启动:" DateUtils.getYmdHms());
}
}
TestJob 这个类实现了 Job 接口,实现了 execute 方法,这里还可以接收参数
这个文件在 com.zyxx.sbm.job 包下面,那么在页面新增定时任务的时候,就需要填写任务类名为:com.zyxx.sbm.job.TestJob
cron 表达式的知识这里就不一一介绍了
2、页面添加定时任务
那么我们的任务类名就是:com.zyxx.sbm.job.TestJobcron 表达式:*/2 * * * * ?,表示两秒钟执行一次参数:我们没有传入参数
3、后台添加定时任务
packagecom.zyxx.sbm.service.impl;
importcom.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
importcom.baomidou.mybatisplus.core.metadata.IPage;
importcom.baomidou.mybatisplus.extension.plugins.pagination.Page;
importcom.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
importcom.zyxx.common.shiro.SingletonLoginUtils;
importcom.zyxx.common.utils.DateUtils;
importcom.zyxx.common.utils.LayTableResult;
importcom.zyxx.common.utils.ResponseResult;
importcom.zyxx.sbm.entity.SysQuartz;
importcom.zyxx.sbm.mapper.SysQuartzMapper;
importcom.zyxx.sbm.service.SysQuartzService;
importlombok.extern.slf4j.Slf4j;
importorg.apache.commons.lang3.StringUtils;
importorg.quartz.*;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Service;
importjava.util.List;
/**
* <p>
* 定时任务信息表 服务实现类
* </p>
*
*@authorlizhou
*@since2020-07-21
*/
@Slf4j
@Service
publicclassSysQuartzServiceImplextendsServiceImpl<SysQuartzMapper,SysQuartz>implementsSysQuartzService{
@Autowired
privateScheduler scheduler;
/**
* 添加定时任务
*/
@Override
publicResponseResultadd(SysQuartz sysQuartz){
QueryWrapper<SysQuartz> queryWrapper =newQueryWrapper<>();
queryWrapper.eq("class_name", sysQuartz.getClassName());
List<SysQuartz> sysQuartzList = list(queryWrapper);
if(null!= sysQuartzList && !sysQuartzList.isEmpty()) {
returnResponseResult.getInstance().error("该任务类名已经存在");
}
sysQuartz.setCreateTime(DateUtils.getYmdHms());
sysQuartz.setCreateUser(SingletonLoginUtils.getUserId());
save(sysQuartz);
// 启动
if(0== sysQuartz.getQuartzStatus()) {
this.schedulerAdd(sysQuartz.getClassName().trim(), sysQuartz.getCronExpression().trim(), sysQuartz.getParam());
}
returnResponseResult.getInstance().success();
}
/**
* 添加定时任务
*
*@paramclassName
*@paramcronExpression
*@paramparam
*/
@Override
publicvoidschedulerAdd(String className, String cronExpression, String param){
try{
// 启动调度器
scheduler.start();
// 构建job信息
JobDetail jobDetail = JobBuilder.newJob(getClass(className).getClass()).withIdentity(className).usingJobData("param", param).build();
// 表达式调度构建器(即任务执行的时间)
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
// 按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(className).withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail, trigger);
}catch(SchedulerException e) {
log.error(e.getMessage());
}catch(RuntimeException e) {
log.error(e.getMessage());
}catch(Exception e) {
log.error(e.getMessage());
}
}
/**
* 删除定时任务
*
*@paramclassName
*/
@Override
publicvoidschedulerDelete(String className){
try{
scheduler.pauseTrigger(TriggerKey.triggerKey(className));
scheduler.unscheduleJob(TriggerKey.triggerKey(className));
scheduler.deleteJob(JobKey.jobKey(className));
}catch(Exception e) {
log.error(e.getMessage(), e);
}
}
privatestaticJobgetClass(String className)throwsException{
Class<?> class1 = Class.forName(className);
return(Job) class1.newInstance();
}
}
需要注入 Scheduler 对象,使用该对象开启或停止定时任务
在启动定时任务之前,我们应先删除该任务类名开启的定时任务,防止该任务类名已经添加过了
// 删除定时任务
schedulerDelete(sysQuartz.getClassName().trim());
// 添加定时任务
schedulerAdd(sysQuartz.getClassName().trim(), sysQuartz.getCronExpression().trim(), sysQuartz.getParam());
添加定时任务,传入任务类名,cron 表达式,参数
停止定时任务,只需要:
scheduler.pauseJob(JobKey.jobKey(sysQuartz.getClassName().trim()));
根据任务类名,停止定时任务即可
五、开发测试启动项目,在管理界面,开启定时任务,即可在控制台看到打印的信息
表示我们的定时任务已经启动成功了
六、优化建议当我们添加了定时任务并启动后,重新启动项目的时候,定时任务却不会自动启动,这时候,我们就需要在项目启动的时候做一些事情了,也就是系统启动任务
不清楚的同学可以复习一下之前我的博客【SpringBoot】十九、SpringBoot中实现启动任务
importcom.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
importcom.zyxx.sbm.entity.SysQuartz;
importcom.zyxx.sbm.service.SysQuartzService;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.boot.CommandLineRunner;
importorg.springframework.core.annotation.Order;
importorg.springframework.stereotype.Component;
importjava.util.List;
/**
*@ClassNameSystemStartTask
* 项目启动任务--启动定时任务
*@AuthorLizhou
*@Date2020-07-21 12:56:56
**/
@Component
@Order(100)
publicclassSystemQuartzStartTaskimplementsCommandLineRunner{
@Autowired
privateSysQuartzService sysQuartzService;
@Override
publicvoidrun(String... args)throwsException{
// 查询启动的定时任务
QueryWrapper<SysQuartz> queryWrapper =newQueryWrapper<>();
queryWrapper.eq("status",0);
queryWrapper.eq("quartz_status",0);
List<SysQuartz> list = sysQuartzService.list(queryWrapper);
if(null!= list && !list.isEmpty()) {
for(SysQuartz item : list) {
// 删除定时任务
sysQuartzService.schedulerDelete(item.getClassName().trim());
// 添加定时任务
sysQuartzService.schedulerAdd(item.getClassName().trim(), item.getCronExpression().trim(), item.getParam());
}
}
}
}
从数据库查询出启动的定时任务,并将他们添加到定时任务启动中,这样项目一启动时,就会自动启动我们定义的定时任务了
最后
任务类名的正则表达式
/^[a-zA-Z] (\.([a-zA-Z]) ) $/
cron 表达式的验证使用正则太麻烦,可以使用 Quartz 自带验证方法
CronExpression.isValidExpression(cron)
SpringBoot 中使用 Quartz 管理定时任务的学习就到这儿了,其实也并不难理解,相比于之前用的定时任务是不是好很多了呢,别忘了最后加上系统启动任务哦
如您在阅读中发现不足,欢迎留言!!!
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:
https://blog.csdn.net/qq_40065776/article/details/107489728
,