首先对于Quartz的原理和使用这里不再做赘述和讲解,相信大家可以自信查阅文档进行使用。先说一下个人的这个使用背景:项目中需要引入定时任务,框架是springcloud分布式系统然后调研之后决定引入Quartz,他需要基于数据库特定的表来存储定时任务相关的数据等,普通的定时任务比如:日终定时批量进行某些数据的处理扫描等也可以使用,不过那个需要项目启动后就将任务进行添加并启动。对于特定的动态生成的任务:比如前端进行提交某些数据调用服务端接口时需要根据业务需求生成一个未来的时间进行执行的任务逻辑。费话不多少直接上干货!
本地配置文件的简洁版
server:
port: 7070
spring:
application:
name: kmen
profiles:
active: dev
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848
file-extension: yaml
group: DEFAULT_GROUP
datasource:
driver-class-name : com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/kmen?useSSL=false&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai
username: 34174f6cd825c31110efcea7889cc35e
password: 8950f2f53d356857bb2f0e99d9ccec25
type: com.luso.em.config.MyDatasource
hikari:
minimum-idle: 5
maximum-pool-size: 15
auto-commit: true
idle-timeout: 30000
pool-name: DatebookHikariCP
max-lifetime: 1800000
connection-timeout: 30000
connection-test-query: SELECT 1
quartz:
properties:
org:
quartz:
scheduler:
instanceName: kmen
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
redis:
host: localhost
port: 6379
数据库的表sql文件https://download.csdn.net/download/K_Men/75787778如果是普通的日终定时任务则使用方式之一:
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Slf4j
@Order(1)
public class QuartzJobRunner implements ApplicationRunner {
@Autowired
private QuartzJobManager quartzJobManager;
@Override
public void run(ApplicationArguments args) {
try {
log.info("固定的定时任务启动位置 ");
// 添加自启动的定时任务
// quartzJobManager.addJob(CloseApplyTask.class, "0 44 10 10 1 ? 2022", null,"jobName");
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}
核心添加和删除定时任务类
import com.luso.base.core.exception.LoanCloudException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
@Slf4j
public class QuartzJobManager {
private static final String JOB_DEFAULT_GROUP_NAME = "job_group_loan_em_";
private static final String TRIGGER_DEFAULT_GROUP_NAME = "trigger_group_loan_em_";
private static final String JOB_DEFAULT_NAME = "jobName_";
private static final String TRIGGER_DEFAULT_NAME = "trigger_";
@Autowired
private Scheduler scheduler;
/**
* 添加定时任务
*
* @param jobClass 需要执行的业务逻辑service类
* @param cronExp cron表达式
* @param dataMap 需要传递以及存储的数据
* @param jobName 全局唯一的job key名称
* @return
*/
public void addJob(Class<? extends Job> jobClass, String cronExp, Map<String, Object> dataMap, String jobName) {
try {
if (!CronExpression.isValidExpression(cronExp)) {
log.error("invalid cron expression: {}", cronExp);
throw new SchedulerException("invalid cron expression");
}
JobDetail jobDetail = JobBuilder.newJob(jobClass)
.withIdentity(new JobKey(StringUtils.join(JOB_DEFAULT_NAME, jobName), StringUtils.join(JOB_DEFAULT_GROUP_NAME, jobName)))
.build();
if (dataMap != null && dataMap.size() > 0) {
jobDetail.getJobDataMap().putAll(dataMap);
}
CronTrigger trigger = TriggerBuilder.newTrigger()
.forJob(jobDetail)
.withIdentity(new TriggerKey(StringUtils.join(TRIGGER_DEFAULT_NAME, jobName), StringUtils.join(TRIGGER_DEFAULT_GROUP_NAME, jobName)))
.withSchedule(CronScheduleBuilder.cronSchedule(cronExp))
.build();
scheduler.scheduleJob(jobDetail, trigger);
if (!scheduler.isShutdown()) {
scheduler.start();
}
} catch (Exception e) {
log.error(e.getMessage());
throw new LoanCloudException(e);
}
}
/**
* 删除定时任务
*
* @param jobName 全局唯一的job key名称(与添加任务时传递的一致)
* @return
*/
public void deleteJob(String jobName) {
try {
JobKey jobKey = new JobKey(StringUtils.join(JOB_DEFAULT_NAME, jobName), StringUtils.join(JOB_DEFAULT_GROUP_NAME, jobName));
if (!scheduler.checkExists(jobKey)) {
log.info("job not exists, job name: {}, group name: {}", jobKey.getName(), jobKey.getGroup());
return;
}
TriggerKey triggerKey = TriggerKey.triggerKey(StringUtils.join(TRIGGER_DEFAULT_NAME, jobName), StringUtils.join(TRIGGER_DEFAULT_GROUP_NAME, jobName));
scheduler.pauseTrigger(triggerKey);
scheduler.unscheduleJob(triggerKey);
scheduler.deleteJob(jobKey);
} catch (Exception e) {
log.error(e.getMessage());
throw new LoanCloudException(e);
}
}
}
动态添加定时任务时直接在业务代码里增加调用即可
@Autowired
private QuartzJobManager quartzJobManager;
//添加
quartzJobManager.addJob(CloseApplyTask.class, cronExp, map, "全局唯一得job name");
//删除
quartzJobManager.deleteJob("全局唯一得job name");
有一点需要给大家说一下,因为我的定时任务是指定具体的时间执行只需要执行一次的,所以当执行完成后quartz相关表的数据会自行物理删除掉。以上的代码都在项目中执行过且有效。配置文件中的quartz的配置都是很重要的且不可缺少的,我直接使用了相关的数据库库连接包括数据库的用户名和密码都是非明文加密过后的数据。