SpringBoot中实现quartz定时任务

Quartz整合到SpringBoot(持久化到数据库)

背景

最近完成了一个小的后台管理系统的权限部分,想着要扩充点东西,并且刚好就完成了一个自动疫情填报系统,但是使用的定时任务是静态的,非常不利于扩展和调控,就想到了用Quartz实现。

Quartz简介

Quartz是一个优秀的任务调度框架,有静态任务调度和动态任务调度两种类型。静态任务调度是编写好代码,然后在启动的时候,将任务保存在内内存中,也就是下面的RAMJobStore,实现相对简单;动态任务调度主要是持久化到数据库,即下面的JDBC作业存储,实现方式相对复杂一点,但是可操作性更强。

  • RAMJobStore :RAM也就是内存,默认情况下Quartz会将任务调度存在内存中,这种方式性能是最好的,因为内存的速度是最快的。不好的地方就是数据缺乏持久性,但程序崩溃或者重新发布的时候,所有运行信息都会丢失
  • JDBC作业存储:存到数据库之后,可以做单点也可以做集群,当任务多了之后,可以统一进行管理。关闭或者重启服务器,运行的信息都不会丢失。缺点就是运行速度快慢取决于连接数据库的快慢。

Quartz相关概念

  • Scheduler:调度器,进行任务调度;quartz的大脑

  • Job:业务job,亦可称业务组件;定时任务的具体执行业务需要实现此接口,调度器会调用此接口的execute方法完成我们的定时业务

  • JobDetail:用来定义业务Job的实例,我们可以称之为quartz job,很多时候我们谈到的job指的是JobDetail

  • Trigger:触发器,用来定义一个指定的Job何时被执行

  • JobBuilder:Job构建器,用来定义或创建JobDetail的实例;JobDetail限定了只能是Job的实例

  • TriggerBuilder:触发器构建器,用来定义或创建触发器的实例

RAMJobStore的实现

整体流程

  • 首先需要创建任务(Job),比如取消订单、定时发送短信邮件之类的,这是我们的任务主体,也是写业务逻辑的地方。

  • 创建任务调度器(Scheduler),这是用来调度任务的,主要用于启动、停止、暂停、恢复等操作,也就是那几个api的用法。

  • 创建任务明细(JobDetail),最开始我们编写好任务(Job)后,只是写好业务代码,并没有触发,这里需要用JobDetail来和之前创建的任务(Job)关联起来,便于执行。

  • 创建触发器(Trigger),触发器是来定义任务的规则的,比如几点执行,几点结束,几分钟执行一次等等。这里触发器主要有两大类(SimpleTrigger和CronTrigger)。

  • 根据Scheduler来启动JobDetail与Trigger

导入依赖

<!--quartz定时调度依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

创建Job

要求: 需实现Job接口,并且这个接口就一个execute()方法需要重写,方法内容就是具体的业务逻辑。如果是动态任务呢,比如取消订单,每次执行都是不同的订单号。这个时候就需要在创建任务(JobDetail)或者创建触发器(Trigger)的那里传入参数,然后在这里通过JobExecutionContext来获取参数进行处理,

/**
 * @author Mr.zhou
 * @version 1.0
 * @date 2020/11/17 17:52
 */
public class TestJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.err.println("Hello quartz, " + jobExecutionContext.getJobDetail().getJobDataMap().getString("message"));
        System.err.println("Hello quartz, " + jobExecutionContext.getMergedJobDataMap().getString("work"));
        System.err.println();
    }
}

创建任务调度器

这里我们用的是SpringBoot,SpringBoot会自动帮我们装配任务调度器,在使用的时候,直接注入即可。

@Resource
private Scheduler scheduler;

如果没用使用SpringBoot,那么就需要手动创建了。通常优秀的框架,创建某些核心类都会使用工厂模式或者构建者模式,值得学习。

SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();

创建任务明细:JobDetail

// 创建任务详情
JobDetail jobDetail = JobBuilder.newJob(TestJob.class)
        // 添加参数
        .usingJobData("message", "米西米西滑不拉几")
        // 添加认证信息,共有三种认证方式
        .withIdentity(orderNum)
        .build();

创建触发器:Trigger

SimpleSchedule策略
// 创建触发器
Trigger trigger = TriggerBuilder.newTrigger()
        // 添加参数
        .usingJobData("work", "我在写代码,你呢?")
        // 认证信息
        .withIdentity(orderNum)
        // 开始时间
        .startAt(start)
        // 执行策率,有SimpleSchedule和CronSchedule两种
        .withSchedule(
                SimpleScheduleBuilder.simpleSchedule()
                .withIntervalInSeconds(5)
                .repeatForever())
        .build();
CronSchedule策略
// 创建触发器
Trigger trigger = TriggerBuilder.newTrigger()
        // 添加参数
        .usingJobData("work", "我在写代码,你呢?")
        // 认证信息
        .withIdentity(orderNum)
        // 开始时间
        .startNow()
        // 执行策率,有SimpleSchedule和CronSchedule两种
        .withSchedule(CronScheduleBuilder.cronSchedule("*/5 * * * * *"))
        .build();

注意:.startNow().startAt()这里有个坑,这两个方法是对同一个成员变量进行修改的 也就是说startAt和startNow同时调用的时候任务开始的时间是按后面调用的方法为主的,谁写在后面用谁。看看这里的源码:

在这里插入图片描述

启动任务

上面都已经将工作完成了,接下来就是启动任务了

// 启动定时任务
scheduler.scheduleJob(jobDetail, trigger);
if (!scheduler.isShutdown()) {
    scheduler.start();
}

实现任务的常规操作

上面已经介绍了怎么去定义一个任务,并成功启动,下面就简单介绍任务的启动、暂停、恢复、以及删除等操作。

@RestController
@RequestMapping("/quartz")
public class QuartzController {

    @Resource
    private Scheduler scheduler;

    /**
     * 启动一个定时任务
     * @param orderNum 编号
     * @return 结果
     * @throws SchedulerException 异常
     */
    @PostMapping("/start")
    public R quartz(@RequestParam("orderNum") String orderNum) throws SchedulerException {
        // 当前时间10秒之后
        Date start = new Date(System.currentTimeMillis() + 10 * 1000);

        // 创建任务详情
        JobDetail jobDetail = JobBuilder.newJob(TestJob.class)
                // 添加参数
                .usingJobData("message", "米西米西滑不拉几")
                // 添加认证信息,共有三种认证方式
                .withIdentity(orderNum)
                .build();

        // 创建触发器
        Trigger trigger = TriggerBuilder.newTrigger()
                // 添加参数
                .usingJobData("work", "我在写代码,你呢?")
                // 认证信息
                .withIdentity(orderNum)
                // 开始时间
                .startAt(start)
                // 执行策率,有SimpleSchedule和CronSchedule两种
                .withSchedule(CronScheduleBuilder.cronSchedule("*/5 * * * * ?"))
                .build();
        // 启动定时任务
        scheduler.scheduleJob(jobDetail, trigger);
        if (!scheduler.isShutdown()) {
            scheduler.start();
        }
        System.err.println("定时任务启动成功");
        return R.ok();
    }


    /**
     * 任务关闭
     * @param oderNum 标识
     * @return 结果
     * @throws SchedulerException 异常
     */
    @PostMapping("/shutdown")
    public R shutdown(@RequestParam("orderNum") String oderNum) throws SchedulerException {
        scheduler.pauseTrigger(TriggerKey.triggerKey(oderNum));
        return R.ok();
    }


    /**
     * 任务恢复
     * @param oderNum 标识
     * @return 结果
     * @throws SchedulerException 异常
     */
    @PostMapping("/resume")
    public R resume(@RequestParam("orderNum") String oderNum) throws SchedulerException {
        scheduler.resumeTrigger(TriggerKey.triggerKey(oderNum));
        return R.ok();
    }

    /**
     * 任务删除
     * @param oderNum 标识
     * @return 结果
     * @throws SchedulerException 异常
     */
    @PostMapping("/del")
    public R del(@RequestParam("/oderNum") String oderNum) throws SchedulerException {
        scheduler.pauseTrigger(TriggerKey.triggerKey(oderNum));
        scheduler.unscheduleJob(TriggerKey.triggerKey(oderNum));
        scheduler.deleteJob(JobKey.jobKey(oderNum));
        return R.ok();
    }

}

结果示例

由于我项目已经集成了Swagger文档,所以我就直接在这上面进行接口测试了

  • 开启任务
    在这里插入图片描述

  • 任务启动之后的输出效果

在这里插入图片描述

到这里,应该就清楚了Quartz和SpringBoot整合,大致流程,了解了RAMJobStore如何实现,那么数据库持久化的实现也应该有了基本思路了。

JDBC作业存储实现

大致流程

  • 创建SpringBoot工程,并且加入Web和Quartz依赖
  • 下载Quartz官方提供的数据库脚本,注意版本,并将其导入到自己项目的数据库中
  • 添加Quartz配置
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值