相关文章推荐
SpingBoot2.X+Quartz实现任务调度

SpingBoot2.X+Quartz实现任务调度

SpringBoot任务调度之-Quartz

在SpringBoot中实现定时任务,我常用的有以下两种:
  • SpringTask:spring自主研发的定时任务工具,并且存在于Spring体系中,不需要添加任何依赖。
  • Quartz:是一个开源的任务调度服务,几乎可以集成到任务Java应用程序中
    昨天已经介绍了springTask,

今天来介绍Quartz,他是一个强大的开源任务调度工具,可以实现复杂定时任务,使用SprngBoot+Mybatis+Quartz+Swagger实现定时任务的 增删改查,启用和停用

设计Meaven

  • Mybatis (使用的数据据版本是8.0)使用5.7的会有问题
  • Quartz
  • Swagger

Quartz介绍

Quartz时一个开源的定时任务项目,可以单独使用也可以和应用程序结合使用。Quartz可是常见简单Jobs进行运行,也可以运行上万个复杂的Jobs。

Quartz核心API

  • Job (任务):是一个接口,里面有一个方法,可以通过实现Job接口定义需要执行的任务 Job 接口如下:
  package org.quartz;
  public interface Job {
    public void execute(JobExecutionContext context)
      throws JobExecutionException;
  • JobDetail :用于创建Job实例
 public class TestJob implements Job {
    public TestJob() {
    public void execute(JobExecutionContext context)
      throws JobExecutionException
      System.err.println(" TestJob is start executing.");
  public class Test {
    public static void main(String[] args) throws SchedulerException {
  JobDetail job = newJob(HelloJob.class)
      .withIdentity("myJob", "group1") // name "myJob", group "group1"
      .build();
  • Trigger :触发器,描述触发Job执行的时间触发规则实现类SimpleTrigger和CronTrigger可以通过crom表达式定义出各种复杂的调度方案
  • JobBuilder :用于定义JobDetail实例,用于定义Job实例
  • TriggerBuilder :用于构建Trigger实例
  • Scheduler (调度):表示一个独立的Quartz容器,Trigger和JobDetail可以注册到Scheduler中。

代码实现

添加依赖

  <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!--集成druid连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.23</version>
        </dependency>
        <!--Mysql数据库驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>  8.0.16</version>
        </dependency>
        <!--MyBatis Plus 依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.2</version>
        </dependency>
        <!--MyBatis Plus 代码生成器-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.3.2</version>
        </dependency>
        <!--Velocity模板引擎-->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.2</version>
        </dependency>
        <!--Swagger-UI API文档生产工具-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
            <exclusions>
                <exclusion>
                    <artifactId>swagger-models</artifactId>
                    <groupId>io.swagger</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>swagger-annotations</artifactId>
                    <groupId>io.swagger</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
        <!--解决Swagger 2.9.2版本NumberFormatException-->
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-models</artifactId>
            <version>1.6.0</version>
        </dependency>
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-annotations</artifactId>
            <version>1.6.0</version>
        </dependency>
        <!--Hutool Java工具包-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.5.7</version>
        </dependency>
    </dependencies>

在application.yml配置Quartz

:本文介绍的是定时任务持久化到数据库中,因此(具体可参考官网)

  • jobStore:class : org.quartz.impl.jdbcjobstore.JobStoreTX
server:
  port: 9999
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
    username: root
    password: zbb920604
  quartz:
    properties:
        quartz:
          scheduler:
            instanceName: clusteredScheduler
            instanceId: AUTO
          jobStore:
            class: org.quartz.impl.jdbcjobstore.JobStoreTX
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
            tablePrefix: qrtz_
            isClustered: true
            clusterCheckinInterval: 10000
            useProperties: false
          threadPool:
            class: org.quartz.simpl.SimpleThreadPool
            threadCount: 10
            threadPriority: 5
            threadsInheritContextClassLoaderOfInitializingThread: true
    job-store-type: jdbc
#mybatis-plus:
#  mapper-locations: classpath*:/mapper/**/**Mapper.xml
mybatis:
  mapper-locations:
    - classpath:mapper/*.xml
    - classpath*:com/**/mapper/*.xml

建立将定时任务持久化到数据库所需要的表

定时任务所需要的表实际上已经在Quartz依赖中 路径如下:

  • \org\quartz\impl\jdbcjobstore


Quartz表介绍

添加输入参数类

package com.cn.greemes.quartzdemo.dto;
import lombok.Data;
@Data
public class QuartzVo {
     * 定时任务类全称
    private String jobClassName;
     * 定时任务所属组
    private String jobGroupName;
     * cron 表达式
    private String cron;

添加配置

@Configuration
public class SchedulerConfig implements SchedulerFactoryBeanCustomizer {
    @Autowired
    private DataSource dataSource;
    @Override
    public void customize(SchedulerFactoryBean schedulerFactoryBean) {
        try {
            System.out.println(dataSource.getConnection());
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        // 启动延时
        schedulerFactoryBean.setStartupDelay(10);
        // 自动启动任务调度
        schedulerFactoryBean.setAutoStartup(true);
        // 是否覆盖现有作业定义
        schedulerFactoryBean.setOverwriteExistingJobs(true);
        // 配置数据源
        schedulerFactoryBean.setDataSource(dataSource);

添加Job

  • BaseJob
package com.cn.greemes.quartzdemo.job;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public interface BaseJob extends Job {
    @Override
    void execute(JobExecutionContext context) throws JobExecutionException;
  • MyJob用于测试
package com.cn.greemes.quartzdemo.job;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.Date;
import java.util.List;
public class MyJob implements BaseJob{
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("myjob任务开始");
        System.out.println("定时任务执行时间"+new Date());

在Controller层添加增删改查

package com.cn.greemes.quartzdemo.model.quartz.controller;
import com.cn.greemes.quartzdemo.Job.BaseJob;
import com.cn.greemes.quartzdemo.common.CommonResult;
import com.cn.greemes.quartzdemo.common.ResultCode;
import com.cn.greemes.quartzdemo.dto.QuartzVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.print.DocFlavor;
import java.util.Date;
@Controller
@Api(tags = "JobController", description = "任务管理")
@RequestMapping("/Job")
public class JobController {
    private static final Logger LOGGER = LoggerFactory.getLogger(JobController.class);
    @Autowired
    Scheduler scheduler;
     * 新增job任务
     * @param quartzVo
     * @return
     * @throws Exception
    @ApiOperation(value = "新增Job服务")
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult addJob(@RequestBody QuartzVo quartzVo) throws Exception {
        String jobName = quartzVo.getJobClassName();
        String cron = quartzVo.getCron();
        String jobGroupName = quartzVo.getJobGroupName();
        //校验cron表达式 是否符合规范
        boolean b = CronExpression.isValidExpression(cron);
        if (!b){
            return CommonResult.failed("cron表达式书写有误,请重新提交");
        // 启动调度器
        scheduler.start();
        //构建job信息
        JobDetail jobDetail = JobBuilder.newJob(getClass(jobName).getClass()).withIdentity(jobName, jobGroupName).build();
        //cron表达式调度器构建
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
        //构建 Trigger
        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName).withSchedule(scheduleBuilder).build();
        Date date = scheduler.scheduleJob(jobDetail, cronTrigger);
        if (date==null){
            return CommonResult.failed("添加定时任务失败");
        return CommonResult.success(ResultCode.SUCCESS);
    @ApiOperation(value = "修改Job服务")
    @RequestMapping(value = "/update", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult updateJob(@RequestBody QuartzVo quartzVo) throws SchedulerException {
        String jobName = quartzVo.getJobClassName();
        String cron = quartzVo.getCron();
        String jobGroupName = quartzVo.getJobGroupName();
        //校验cron表达式 是否符合规范
        boolean b = CronExpression.isValidExpression(cron);
        if (!b){
            return CommonResult.failed("cron表达式书写有误,请重新提交");
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        //重新构建表达式trigger
        trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
        Date date = scheduler.rescheduleJob(triggerKey, trigger);
        if (date==null){
            return CommonResult.failed("添加定时任务失败");
        return CommonResult.success(ResultCode.SUCCESS);
    @ApiOperation(value = "删除Job服务")
    @RequestMapping(value = "/delete", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult deleteJob(@RequestBody QuartzVo quartzVo) throws SchedulerException {
        String jobName = quartzVo.getJobClassName();
        String jobGroup = quartzVo.getJobGroupName();
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
        scheduler.pauseTrigger(triggerKey);
        scheduler.unscheduleJob(triggerKey);
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        boolean deleteJob = scheduler.deleteJob(jobKey);
        if (!deleteJob){
            return CommonResult.failed("删除定时任务失败");
        return CommonResult.success(ResultCode.SUCCESS);
    @ApiOperation(value = "启动定时任务Job服务")
    @RequestMapping(value = "/start", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult startJob(@RequestBody QuartzVo quartzVo) throws SchedulerException {
        String jobClassName = quartzVo.getJobClassName();
        String jobGroupName = quartzVo.getJobGroupName();
        scheduler.resumeJob(JobKey.jobKey(jobClassName,jobGroupName));
        return CommonResult.success(ResultCode.SUCCESS);
    @ApiOperation(value = "暂停Job服务")
    @RequestMapping(value = "/stop", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult stopJob(@RequestBody QuartzVo quartzVo) throws SchedulerException {
        String jobClassName = quartzVo.getJobClassName();
         String jobGroupName = quartzVo.getJobGroupName();
        scheduler.pauseJob(JobKey.jobKey(jobClassName,jobGroupName));
        return CommonResult.success(ResultCode.SUCCESS);
    private BaseJob getClass(String jobName) throws Exception {
        String name = "com.cn.greemes.quartzdemo.Job."+jobName;
        Class<?> class1 = Class.forName(name);
        return (BaseJob) class1.newInstance();
 
推荐文章