1、入门案例
官方文档:http://www.quartz-scheduler.org/documentation/quartz-2.3.0/
参考文章:https://mp.weixin.qq.com/s/A-Kv0KUMtlToshRfptpDUQ
配置文件quartz.properties(放到classpath路径下):
org.quartz.scheduler.instanceName = MyScheduler
org.quartz.threadPool.threadCount = 3 # 线程数量,支持最多3个定时任务同时运行
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore # 将定时任务信息存储在内存中
任务类:
import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
@Slf4j
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) {
log.info("hello,quartz!name={},group={}",jobExecutionContext.getJobDetail().getKey().getName(),jobExecutionContext.getJobDetail().getKey().getGroup());
}
}
Main方法:
import cn.hutool.core.date.DateUtil;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzMain {
public static void main(String[] args) throws SchedulerException {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity("hello job").usingJobData("name",1).usingJobData("age",2).build();
SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity("hello trigger").startNow().usingJobData("name",3).usingJobData("age",4)
.startAt(DateUtil.parseDateTime("2022-08-18 11:05:00")).endAt(DateUtil.parseDateTime("2022-08-18 11:06:00"))
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInMilliseconds(3000L).repeatForever()).build();
scheduler.scheduleJob(job,trigger);
scheduler.shutdown();
}
}
2、集成到Spring环境中
配置类(代替quartz.properties了):
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import java.util.Properties;
@Configuration
public class ScheduleConfig {
@Bean
public SchedulerFactoryBean schedulerFactoryBean(MultipleDataSource multipleDataSource) {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
// 注意:MultipleDataSource是我司自定义的复合数据源,读者可不必关注,正常注入DataSource即可
factory.setDataSource(multipleDataSource.getDataSource("LbiDB"));
// quartz参数
Properties prop = new Properties();
prop.put("org.quartz.scheduler.instanceName", "lebi_scheduler");
// 线程池配置
prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
prop.put("org.quartz.threadPool.threadCount", "10");
// JobStore配置
prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
factory.setQuartzProperties(prop);
factory.setSchedulerName("lebi_scheduler");
return factory;
}
}
工具类:
package com.fenqile.platform.bi.quartz;
import org.quartz.*;
public class ScheduleUtils {
/**
* 创建定时任务
*/
public static void createScheduleJob(Scheduler scheduler,String name,String group,String cron,int misfirePolicy,int status) throws Exception {
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class).withIdentity(name,group).build();
// cron表达式调度构建器
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
cronScheduleBuilder = handleCronScheduleMisfirePolicy(misfirePolicy, cronScheduleBuilder);
// 按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(name, group)
.withSchedule(cronScheduleBuilder).build();
// 判断是否存在
if (scheduler.checkExists(JobKey.jobKey(name,group))) {
// 防止创建时存在数据问题 先移除,然后在执行创建操作
scheduler.deleteJob(JobKey.jobKey(name, group));
}
scheduler.scheduleJob(jobDetail, trigger);
// 暂停任务
if (status == 1) {
scheduler.pauseJob(JobKey.jobKey(name, group));
}
}
/**
* 设置定时任务策略
*/
public static CronScheduleBuilder handleCronScheduleMisfirePolicy(int misfirePolicy, CronScheduleBuilder cb) {
switch (misfirePolicy) {
case 1:
return cb;
case 2:
return cb.withMisfireHandlingInstructionIgnoreMisfires();
case 3:
return cb.withMisfireHandlingInstructionFireAndProceed();
case 4:
return cb.withMisfireHandlingInstructionDoNothing();
default: ;
}
return cb;
}
/**
* 0 启动 1 暂停
*/
public static void changeStatus(Scheduler scheduler,int status,String name,String group) throws SchedulerException {
if(0 == status){
scheduler.resumeJob(JobKey.jobKey(name,group));
}else if(1 == status){
scheduler.pauseJob(JobKey.jobKey(name, group));
}
}
}
通过Spring bean创建任务:
import lombok.extern.slf4j.Slf4j;
import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service("schedulerService")
@Slf4j
public class SchedulerServiceImpl implements SchedulerService {
@Autowired
private Scheduler scheduler;
@Override
public StrongCommonResp<String> submitTask(SchedulerReq schedulerReq) {
try {
ScheduleUtils.createScheduleJob(scheduler,schedulerReq.getName(),schedulerReq.getGroup(),
schedulerReq.getCron(),schedulerReq.getMisfirePolicy(),schedulerReq.getStatus());
} catch (Exception e) {
log.error("创建任务失败",e);
return StrongCommonResp.fail("创建任务失败");
}
return StrongCommonResp.success("submitTask success",null);
}
}
3、总结
quartz的分布式定时调度是基于数据库表的,这些表不用我们去创建,quartz会在启动时自己去连接数据库创建这些表。
当多个quartz应用构成一个quartz集群时,quartz会用负载均衡策略保证某一个定时任务在某一个时间点触发时,只会有一个quartz应用去执行。