java quartz 销毁任务_springboot整合quartz实现动态添加、修改、删除、停止job(一)

本文介绍了如何在Spring Boot中集成Quartz,实现动态添加、修改、删除和停止job。通过配置quartz.yml文件,利用MySQL作为数据源,并提供了代码示例进行逻辑实现,包括CronUtil、DateUtils等工具类,以及QuartzJobComponent用于CRUD操作。
摘要由CSDN通过智能技术生成

什么是Quartz?

一个定时任务调度框架,简单易用,功能强大可以使实现定时任务的。

优点:支持集群下定时任务处理

支持任务并发阻塞(上一个任务完成后,才能继续下一个任务)

支持通过API对任务的操作,例如新增任务、修改、启动、暂停、停止(可以在代码中进行调用,而无需修改配置文件再次部署)

支持的数据库种类被较多

目标在Spring Boot中集成Quartz

使用MySql数据库(程序自动导入,无需人工执行脚本)

使用Spring 自身配置的数据源(不再单独配置qz数据源)

通过代码实现动态化添加、修改、暂停、终止job

开发环境JDK版本1.8

Spring Boot 版本:2.3.3.RELEASE

开发工具:eclipse

开发实践

本章节将从Pom依赖配置开始,直到成功运行起该程序为止,为各位朋友提供真实可行的代码实现

pom配置

关于Pom.xml中的配置,有两种方式,第一种使用spring-boot封装的依赖,第二种使用org.quartz的依赖

第一种方式:

org.springframework.boot

spring-boot-starter-quartz

这种依赖的好处是你不需要考虑qz的版本号,Spring boot会根据自身的版本来适应不同的quartz版本,但是缺点也很明显,你无法使用其他版本的quartz(不同版本的QZ结构稍有差异),而且在这个封装的依赖中,其实里面也仅仅是指定了org.quartz的依赖,并没有其他的配置或者逻辑

第二种方式

org.quartz-scheduler

quartz

2.3.2

org.quartz-scheduler

quartz-jobs

2.3.2

这种方式是直接引用的quartz,就是第一种方式中的配置的依赖,但是在这里你就可以自己选择quartz的版本(注意:不同版本的qz结构有差异,Spring boot读取文件时有可能会出现问题。例如在Spring boot 2.3.3.RELEASE中,2.2.1的版本自动生成表结构时会报错--jar包中没有对应的sql脚本,而2.3.2就不存在这个问题)

您可以根据自己的需求来选择哪种依赖方式(以上两种只需要使用其中任何一种即可,无需都使用)

quartz.yml配置################### Quartz配置 start ##################################################

server:

port: 8080

servlet:

context-path: /quartz

spring:

application:

name: demo

#连接池配置

datasource:

#账号配置

url: jdbc:mysql://localhost:3306/qz_table?allowMultiQueries=true&useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Asia/Shanghai

username: root

password: 123456

driver-class-name: com.mysql.cj.jdbc.Driver

#hikari数据库连接池

hikari:

pool-name: Retail_HikariCP

minimum-idle: 5 #最小空闲连接数量

idle-timeout: 180000 #空闲连接存活最大时间,默认600000(10分钟)

maximum-pool-size: 10 #连接池最大连接数,默认是10

auto-commit: true  #此属性控制从池返回的连接的默认自动提交行为,默认值:true

max-lifetime: 1800000 #此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟

connection-timeout: 30000 #数据库连接超时时间,默认30秒,即30000

connection-test-query: SELECT 1

quartz:

#          dataSource:

#            default:

#              driver: com.mysql.jdbc.Driver

#              URL: jdbc:mysql://localhost:3306/jobconfig?useUnicode=true&characterEncoding=utf8

#              user: root

#              password: 12345678

#              maxConnections: 5

#相关属性配置

properties:

org:

quartz:

scheduler:

instanceName: quartzScheduler

instanceId: AUTO

jobStore:

class: org.quartz.impl.jdbcjobstore.JobStoreTX

driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate

tablePrefix: qrtz_

isClustered: false

clusterCheckinInterval: 10000

useProperties: false

threadPool:

class: org.quartz.simpl.SimpleThreadPool

threadCount: 10

threadPriority: 5

threadsInheritContextClassLoaderOfInitializingThread: true

#数据库方式

job-store-type: JDBC

#初始化表结构

jdbc:

initialize-schema: never

#mybatis配置

mybatis:

type-aliases-package: com.example.demo.entity

mapper-locations: classpath:mapper/*.xml

#分页配置, pageHelper是物理分页插件

pagehelper:

#4.0.0以后版本可以不设置该参数,该示例中是5.1.4

helper-dialect: mysql

#启用合理化,如果pageNum<1会查询第一页,如果pageNum>pages会查询最后一页

reasonable: true

################### Quartz配置 End ###################################################

注意:本文配置使用的是yml文件方式,如果您想使用.properties方式,请将上面的冒号改成等号

本文中使用的quartz没有单独配置数据源,而是使用的您在Spring boot中已经配置的数据源(自动识别,可以看下源码,默认支持C3p0,hikari等几种)

本文中默认表结构初始化方式为initialize-schema: never(共有三种方式:always-每次启动都初始化数据库,never-不初始化表结构,embedded,您可以在首次运行时将此方式设置为always,然后再改成never)

在这个配置中dataSource注释掉了,如果您需要quartz单独配置一套数据源,请放开此部分注释

注意,quartz.yml需要被Spring boot发现(或者直接配置到application.yml中),否则即使配置了也不会起作用,而是使用默认的RAM(内存)去保存定时任务的数据(速度快但是应用重启后会丢失,我在此处就栽跟头了)

到这一步,配置已经完成,接下来就该具体的代码了

逻辑代码实现

该部分java类的结构如下:

664edcb2cfe2f60beda2ad4716e1e2aa.png

common包

common包中的Result.java为返回结果类(controller中使用,如您不想使用,请替换为自己的逻辑)package com.example.demo.common;

import java.util.HashMap;

import java.util.Map;

/**

* @project: 郭鹏飞的博客(wwww.pengfeiguo.com)

* @description: 响应结果类

* @version 1.0.0

* @errorcode

*            错误码: 错误描述

* @author

*         

2020-09-04 825338623@qq.com Create 1.0

* @copyright ©2019-2020

*/

public class Result extends HashMap {

public Result() {

put("code", 200);

}

public static Result error() {

return error(500, "未知异常,请联系管理员");

}

public static Result error(String msg) {

return error(500, msg);

}

public static Result error(int code, String msg) {

Result r = new Result();

r.put("code", code);

r.put("msg", msg);

return r;

}

public static Result ok(Object msg) {

Result r = new Result();

r.put("msg", msg);

return r;

}

public static Result ok(Map map) {

Result r = new Result();

r.putAll(map);

return r;

}

public static Result ok() {

return new Result();

}

@Override

public Result put(String key, Object value) {

super.put(key, value);

return this;

}

}

constant包

这个包中的类存的是quartz中的job和trigger的名字常量package com.example.demo.constant;

/**

* @project: 郭鹏飞的博客(wwww.pengfeiguo.com)

* @description: 常量类

* @version 1.0.0

* @errorcode

*            错误码: 错误描述

* @author

*         

2020-09-04 825338623@qq.com Create 1.0

* @copyright ©2019-2020

*/

public class GloabalConstant {

public static final String QZ_JOB_GROUP_NAME = "JOB_GROUP_NAME";

public static final String QZ_TRIGGER_GROUP_NAME = "TRIGGER_GROUP_NAME";

}

entity包

该包中的实体类为封装添加的job信息的实体类,大家可以根据自己的需求改成自己想要的字段package com.example.demo.entity;

import java.util.Date;

import org.quartz.Job;

import org.quartz.JobDataMap;

import org.quartz.JobExecutionContext;

import org.springframework.util.ClassUtils;

import org.springframework.util.ObjectUtils;

import org.springframework.util.StringUtils;

import lombok.Data;

/**

* @project: 郭鹏飞的博客(wwww.pengfeiguo.com)

* @description: qzmodel。

* @version 1.0.0

* @errorcode

*            错误码: 错误描述

* @author

*         

2020-09-04 825338623@qq.com Create 1.0

* @copyright ©2019-2020

*/

@Data

public class QuartzJobModule {

/**

* 触发器开始时间

*/

private Date startTime;

/**

* 触发器结束时间

*/

private Date endTime;

/**

* job名称

*/

private String jobName;

/**

* job组名

*/

private String jobGroupName;

/**

* 定时器名称

*/

private String triggerName;

/**

* 定时器组名

*/

private String triggerGroupName;

/**

* 执行定时任务的具体操作

*/

private Class jobClass;

/**

* cron表达式

*/

private String cron;

/**

* job的附加信息

*/

private JobDataMap jobDataMap = new JobDataMap();

/**

* 校验

* @return

*/

public boolean verify(){

return !(StringUtils.isEmpty(jobName)

|| StringUtils.isEmpty(jobGroupName)

|| StringUtils.isEmpty(triggerName)

|| StringUtils.isEmpty(triggerGroupName)

|| StringUtils.isEmpty(cron)

//        || CollectionUtils.isEmpty(jobDataMap)

|| ObjectUtils.isEmpty(startTime)

|| ObjectUtils.isEmpty(endTime)

|| !ClassUtils.hasMethod(Job.class, "execute", JobExecutionContext.class)

);

}

}

utils包

这个里面有三个类,CronUtil.java为cron工具类,提供将时间转为cron表达式的工具;DateUtils.java为日期工具类,提供日期格式化的工具类;QuartzJobComponent.java是最重要的,提供job的CRUD操作,前两个类为封装QuartzJobModule中的属性提供的,可以自己实现,但是第三个类最好不要修改,可以直接拿来用。

CronUtil.javapackage com.example.demo.utils;

import java.text.ParseException;

import java.util.Calendar;

import java.util.Date;

/**

* @project: 郭鹏飞的博客(wwww.pengfeiguo.com)

* @description: cron生成工具类

* @version 1.0.0

* @errorcode

*            错误码: 错误描述

* @author

*         

2020-09-04 825338623@qq.com Create 1.0

* @copyright ©2019-2020

*/

public class CronUtil {

/**

* @param batchScheduleModel

* @return

* @Desc 转化cron表达式

*/

public static String convertCronExpression(Date startDate, Date endDate, String[] weeks) {

StringBuffer sb = new StringBuffer();

sb.append(convertSeconds()).append(" ").append(convertMinutes(startDate)).append(" ")

.append(convertHours(startDate, endDate)).append(" ").append(convertDay(startDate, endDate)).append(" ")

.append(convertMonth(startDate, endDate)).append(" ").append(convertWeek(weeks));

return sb.toString();

}

/**

* 获取定时任务开始时间

*

* @param batchScheduleModel

* @return

* @throws ParseException

*/

public static Date getStartDate(Date startDate) throws ParseException {

String yyyyMMddS = DateUtils.date2String(startDate, "yyyyMMdd");

Calendar startCal = Calendar.getInstance();

startCal.setTime(startDate);

int startHour = startCal.get(Calendar.HOUR_OF_DAY);// 小时(calendar.HOUR

// 12小时制,calendar.HOUR_OF_DAY 24小时)

int startMin = startCal.get(Calendar.MINUTE);// 分

String startTime = "2359";

if (startHour 

startTime = startHour + "" + startMin;

}

return DateUtils.string2Date(yyyyMMddS + startTime + "00", "yyyyMMddHHmmss");

}

/**

* 获取定时任务结束时间

*

* @param batchScheduleModel

* @return

* @throws ParseException

*/

public static Date getEndDate(Date endDate) throws ParseException {

String yyyyMMddE = DateUtils.date2String(endDate, "yyyyMMdd");

Calendar startCal = Calendar.getInstance();

startCal.setTime(endDate);

int startHour = startCal.get(Calendar.HOUR_OF_DAY);// 小时(calendar.HOUR

// 12小时制,calendar.HOUR_OF_DAY 24小时)

int startMin = startCal.get(Calendar.MINUTE);// 分

String endTime = "0000";

if (startHour 

endTime = startHour + "" + startMin;

}

return DateUtils.string2Date(yyyyMMddE + endTime + "00", "yyyyMMddHHmmss");

}

/**

* 判断当前时间是否在规则时间范围内

*

* @param timesEntityList

* @return

*/

public static boolean isInRuleTimes(Date startDate, Date endDate) {

Date date = new Date();

Calendar cal = Calendar.getInstance();

cal.setTime(date);

int hour = cal.get(Calendar.HOUR_OF_DAY);// 小时(calendar.HOUR

// 12小时制,calendar.HOUR_OF_DAY 24小时)

int minute = cal.get(Calendar.MINUTE);// 分

Calendar startCal = Calendar.getInstance();

startCal.setTime(date);

int startHour = startCal.get(Calendar.HOUR_OF_DAY);// 小时(calendar.HOUR

// 12小时制,calendar.HOUR_OF_DAY 24小时)

int startMinute = startCal.get(Calendar.MINUTE);// 分

Calendar endCal = Calendar.getInstance();

endCal.setTime(date);

int endHour = endCal.get(Calendar.HOUR_OF_DAY);// 小时(calendar.HOUR

// 12小时制,calendar.HOUR_OF_DAY 24小时)

int endMinute = cal.get(Calendar.MINUTE);// 分

if (startHour 

return true;

}

if (startHour == hour && hour == endHour && startMinute 

return true;

}

if (startHour == hour && startMinute 

return true;

}

if (endHour == hour && minute 

return true;

}

return false;

}

/**

* 抽取cron中的hour

*

* @param batchRuleTimeEntityList

* @return

*/

public static String convertHours(Date startDay, Date endDay) {

Calendar startCal = Calendar.getInstance();

startCal.setTime(startDay);

int startHour = startCal.get(Calendar.HOUR_OF_DAY);// 小时(calendar.HOUR

// 12小时制,calendar.HOUR_OF_DAY 24小时)

Calendar endCal = Calendar.getInstance();

endCal.setTime(endDay);

int endHour = endCal.get(Calendar.HOUR_OF_DAY);// 小时(calendar.HOUR

// 12小时制,calendar.HOUR_OF_DAY 24小时)

StringBuffer sb = new StringBuffer();

sb.append(startHour).append("-").append(endHour);

return sb.toString();

}

/**

* 抽取cron中的minute

*

* @param batchRuleTimeEntityList

* @return

*/

public static String convertMinutes(Date startDay) {

return "* ";

/*

* StringBuffer sb = new StringBuffer();

* batchRuleTimeEntityList.forEach((b)->{

* String start = b.getStartTime();

* String end = b.getEndTime();

* String minS = start.substring(3,5);

* String minE = end.substring(3,5);

* sb.append(minS).append("-").append(minE).append(",");

* });

* return sb.deleteCharAt(sb.length()-1).toString();

*/

}

/**

* 抽取cron中的seconds

*

* @return

*/

public static String convertSeconds() {

return "1";

}

/**

* 抽取cron中的day, 在这个项目里直接返回?

*

* @param startDate

* @param endDate

* @return

*/

public static String convertDay(Date startDate, Date endDate) {

return "?";

/*

* String start = DateUtil.formatDate(DateUtil.YYYYMMDD, startDate);

* String end = DateUtil.formatDate(DateUtil.YYYYMMDD, endDate);

* String dayS = start.substring(6,8);

* String dayE = end.substring(6,8);

* return dayS + "-" + dayE;

*/

}

/**

* 抽取cron中的month

*

* @param startDate

* @param endDate

* @return

*/

public static String convertMonth(Date startDate, Date endDate) {

Calendar startCal = Calendar.getInstance();

startCal.setTime(startDate);

// 获取月份(因为在格里高利历和罗马儒略历一年中第一个月为JANUARY,它为0,最后一个月取决于一年中的月份数,所以这个值初始为0,所以需要加1)

int startMonth = startCal.get(Calendar.MONTH) + 1;

Calendar endCal = Calendar.getInstance();

endCal.setTime(endDate);

// 获取月份(因为在格里高利历和罗马儒略历一年中第一个月为JANUARY,它为0,最后一个月取决于一年中的月份数,所以这个值初始为0,所以需要加1)

int endMonth = endCal.get(Calendar.MONTH) + 1;

return startMonth + "-" + endMonth;

}

/**

* 抽取cron中的week

*

* @param dayOfWeeks

* @return

*/

public static String convertWeek(String[] dayOfWeeks) {

StringBuffer sb = new StringBuffer();

for (String dayOfWeek : dayOfWeeks) {

sb.append(dayOfWeek).append(",");

}

sb.deleteCharAt(sb.length() - 1);

return sb.toString();

}

/**

* 抽取cron中的week

*

* @param dayOfWeeks

* @return

*/

public static String convertWeek(String dayOfWeeks) {

StringBuffer sb = new StringBuffer();

String[] split = dayOfWeeks.split(",");

for (String str : split) {

sb.append(str).append(",");

}

sb.deleteCharAt(sb.length() - 1);

return sb.toString();

}

}

DateUtils.javapackage com.example.demo.utils;

import java.text.ParseException;

import java.text.SimpleDateFormat;

import java.util.Date;

import org.springframework.util.StringUtils;

/**

* @project: 郭鹏飞的博客(wwww.pengfeiguo.com)

* @description: 日期工具类

* @version 1.0.0

* @errorcode

*            错误码: 错误描述

* @author

*         

2020-09-04 825338623@qq.com Create 1.0

* @copyright ©2019-2020

*/

public class DateUtils {

/**

* 模式 :yyyyMMddHHmmss

*/

private static final String YYYYMMDD_HHMMSS = "yyyyMMddHHmmss";

/**

* 模式 :yyyyMMdd

*/

private static final String YYYYMMDD        = "yyyyMMdd";

/**

* 方法说明:日期类型按照指定格式转成字符串.

*

* @param date

*            日期

* @param pattern

*            日期格式

* @return

*/

public static String date2String(Date date, String pattern) {

if (null == date) {

date = new Date();

}

if (StringUtils.isEmpty(pattern)) {

pattern = "yyyy-MM-dd HH:mm:ss";

}

try {

return getDateFormat(pattern).format(date);

}

catch (Exception e) {

throw e;

}

}

/**

* 方法说明:获取指定模式pattern的SimpleDateFormat对象.

*

* @param pattern

*            日期格式

* @return

*/

private static SimpleDateFormat getDateFormat(String pattern) {

return new SimpleDateFormat(pattern);

}

/**

* 方法说明:获取默认模式"yyyyMMdd"的SimpleDateFormat对象.

*

* @return

*/

private static SimpleDateFormat getDateFormat() {

return new SimpleDateFormat(YYYYMMDD);

}

/**

* 日期转换

*

* @param srcStr

*            日期字符串

* @param pattern

*            日期格式

* @return

* @throws ParseException

*/

public static String stringFormat(String srcStr, String pattern) throws ParseException {

Date date = string2Date(srcStr);

return date2String(date, pattern);

}

/**

* 方法说明:日期类型转成yyyyMMdd格式字符串.

*

* @param date

*            日期

* @return

*/

public static String date2String(Date date) {

return date2String(date, YYYYMMDD);

}

/**

* 方法说明:字符串转日期类型.

*

* @param date

*            日期字符串

* @return

* @throws ParseException

* @throws Exception

*/

public static Date string2Date(String date) throws ParseException {

if (date.length() != 16) {

return getDateFormat().parse(date);

}

else {

return getDateFormat(YYYYMMDD_HHMMSS).parse(date);

}

}

/**

* 按照转换规则将日期字符串转换为Date类型的时间

*

* @param dateString

*            要转换的日期字符串

* @param format

*            转换的格式,例如:YYYYMMDD

* @return 转换后的Date类型的日期

* @throws ParseException

* @throws BusinessException

*             异常

*/

public static Date string2Date(String dateString, String format) throws ParseException {

SimpleDateFormat sd1 = new SimpleDateFormat(format);

Date date = sd1.parse(dateString);

return date;

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值