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();