一、什么是Quartz
Quartz 是一个功能强大且广泛使用的开源任务调度框架,用于在 Java 应用程序中实现灵活的定时任务调度。它提供了许多功能,允许你创建和管理定期执行的任务,这些任务可以基于时间规则(例如,每天、每小时、每分钟执行)或者基于特定事件来触发。Quartz 可以帮助你轻松地构建定时任务、周期性任务和复杂的任务调度逻辑。
Quartz 框架的主要特点包括:
-
灵活的任务调度: Quartz 允许你定义多种触发器,例如 SimpleTrigger 和 CronTrigger,以支持不同的触发规则,包括每隔一段时间触发、在特定的时间触发、每天、每周或每月特定的时间触发等。
-
任务持久化: Quartz 可以将任务和触发器存储在数据库中,以实现任务的持久化和可管理性。
-
集群支持: Quartz 支持分布式环境中的任务调度,可以在多台机器上运行,并确保任务只在其中一台机器上执行。
-
错过执行处理: 如果某个任务错过了执行时间,Quartz 可以配置错过执行的处理方式,以保证任务最终会被执行。
-
可监听事件: Quartz 允许你注册监听器以监控任务的执行情况,例如任务的开始、结束等。
-
任务线程池: Quartz 可以管理任务的执行线程池,帮助你更好地控制并发执行。
-
可插拔的任务实现: 你可以实现
org.quartz.Job
接口来定义自己的任务逻辑,Quartz 会根据任务定义来执行任务。 -
多种 API: Quartz 提供了多种编程 API,包括传统的 Java API 和更加方便的 Spring 集成。
Quartz 可以用于多种场景,包括定时数据备份、发送定时通知、数据清理、数据同步等。无论是简单的任务调度还是复杂的定时任务逻辑,Quartz 都能够满足各种需求,并提供了丰富的功能和可定制性。
二、Quartz的三大组成部分(Scheduler、JobDetail、CronTrigger)
Scheduler 属性:
-
schedulerName(String): 调度器的名称,用于区分多个调度器。
-
schedulerInstanceId(String): 调度器的实例ID。
JobDetail 属性:
-
name(String): 任务的名称,必须在同一分组内唯一。
-
group(String): 任务的分组,用于组织和管理任务。
-
jobClass(Class<? extends Job>): 指定实现了
org.quartz.Job
接口的任务类。 -
jobDataMap(JobDataMap): 存储与任务关联的数据,可以在任务执行时使用。
-
durability(boolean): 如果设为
true
,表示即使没有与之关联的触发器,任务也不会被自动删除。 -
requestsRecovery(boolean): 如果设为
true
,任务在失败后将被重新执行。 -
description(String): 任务的描述信息。
JobBuilder 属性及其解释:
JobBuilder
是用于构建 JobDetail
实例的构建器。
-
newJob(Class<? extends Job> jobClass): 创建一个新的
JobBuilder
实例,并指定任务的实现类。 -
withIdentity(String name, String group): 设置任务的名称和分组。
-
usingJobData(JobDataMap jobDataMap): 设置任务的数据。
-
storeDurably(boolean storeDurably): 设置任务是否持久化。
-
requestRecovery(boolean requestsRecovery): 设置任务在失败后是否重新执行。
-
withDescription(String description): 设置任务的描述信息。
CronTrigger 属性:
-
name(String): 触发器的名称,必须在同一分组内唯一。
-
group(String): 触发器的分组,用于组织和管理触发器。
-
cronExpression(String): 定义触发器的Cron表达式,用于定义任务触发的时间规则。
-
timezone(TimeZone): 设置Cron表达式的时区。
-
startTime(Date): 触发器的开始时间。
-
endTime(Date): 触发器的结束时间。
-
priority(int): 触发器的优先级。
-
misfireInstruction(int): 定义触发器错过执行的处理方式。
-
jobDataMap(JobDataMap): 存储与触发器关联的数据,可以在触发器触发时使用。
-
description(String): 触发器的描述信息。
TriggerBuilder 属性及其解释:
TriggerBuilder
是用于构建触发器实例的构建器。
-
newTrigger(): 创建一个新的
TriggerBuilder
实例。 -
withIdentity(String name, String group): 设置触发器的名称和分组。
-
withSchedule(ScheduleBuilder<? extends Trigger> scheduleBuilder): 设置触发器的调度规则,例如
CronScheduleBuilder
。 -
forJob(JobDetail jobDetail): 为触发器关联一个任务。
-
startAt(Date startTime): 设置触发器的开始时间。
-
endAt(Date endTime): 设置触发器的结束时间。
-
withPriority(int priority): 设置触发器的优先级。
-
withMisfireHandlingInstruction(int misfireInstruction): 设置触发器的错过执行处理方式。
-
usingJobData(JobDataMap jobDataMap): 设置触发器的数据。
-
withDescription(String description): 设置触发器的描述信息。
这些属性和构建器方法用于配置和创建 Quartz 中的调度器、任务、触发器,以实现定时任务调度。你可以根据具体需求来调整这些属性,灵活定义任务的执行规则和调度行为。
三、SpringBoot继承Quartz
1、添加maven依赖
<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
2、添加quartz.properties配置文件,放在resource目录下。
spring.quartz.job-store-type=jdbc
spring.quartz.auto-startup=true
spring.quartz.jdbc.initialize-schema=embedded
spring.quartz.properties.org.quartz.scheduler.instanceName=MyScheduler
spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
spring.quartz.properties.org.quartz.jobStore.isClustered=true
spring.quartz.properties.org.quartz.jobStore.useProperties=false
3、在application.yml中添加以下属性,确定线程池的数量,可以同时执行多少个定时任务。
org:
quartz:
threadPool:
class: org.quartz.simpl.SimpleThreadPool
threadCount: 10
threadPriority: 5
threadsInheritContextClassLoaderOfInitializingThread: true
4、创建job实例工厂(解决Spring注入问题,如果使用默认会导致Spring的@Autowired无法注入问题。)
@Component
public class QuartzAdaptableJobFactory extends AdaptableJobFactory {
//AutowireCapableBeanFactory 可以将一个对象添加到SpringIOC容器中,并且完成该对象注入
@Autowired
private AutowireCapableBeanFactory autowireCapableBeanFactory;
/**
* 该方法需要将实例化的任务对象手动的添加到springIOC容器中并且完成对象的注入
*/
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
Object obj = super.createJobInstance(bundle);
// 通过以下方式,解决job任务无法使用spring中的Bean问题
this.autowireCapableBeanFactory.autowireBean(obj);
return obj;
}
}
5、QuartzConfig.java配置类(注册调度工厂)
@Configuration
public class QuartzConfig {
@Autowired
private QuartzAdaptableJobFactory jobFactory;
@Bean(name = "SchedulerFactory")
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
//获取配置属性
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
//在quartz.properties中的属性被读取并注入后再初始化对象
propertiesFactoryBean.afterPropertiesSet();
//创建SchedulerFactoryBean
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setQuartzProperties(propertiesFactoryBean.getObject());
factory.setJobFactory(jobFactory);
return factory;
}
/*
* 通过SchedulerFactoryBean获取Scheduler的实例
*/
@Bean(name = "scheduler")
public Scheduler scheduler() throws IOException, SchedulerException {
Scheduler scheduler = schedulerFactoryBean().getScheduler();
return scheduler;
}
}
6、编写Job具体任务类,实现Job接口,重写execute()方法,此方法里编写对定时任务进行具体的逻辑处理代码。
public class QuartzJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("定时任务执行逻辑");
}
}
7、编写Quartz对外服务层代码----开启、暂停、恢复定时任务
import com.alibaba.fastjson.JSONObject;
import com.mv.equipment.domain.EquipCheckPlan;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
@Component
public class QuartzService {
private static final Logger logger = LoggerFactory.getLogger(QuartzService.class);
private static QuartzService jobUtil;
@Autowired
private Scheduler scheduler;
public QuartzService() {
logger.info("init QuartzService");
jobUtil = this;
}
public static QuartzService getInstance() {
logger.info("return JobCreateUtil");
return QuartzService.jobUtil;
}
/**
* 创建计划job
* @throws Exception
* @author qianguojie 0/5 * * * * ?
* @date 2023/3/30.
*/
public void addEquipCheckJob(EquipCheckPlan equipCheckPlan) throws Exception {
Date startDate = equipCheckPlan.getNextTime();
Date endDate = equipCheckPlan.getEndTime();
// 启动调度器
scheduler.start();
// 构建job信息
JobDetail jobDetail = JobBuilder
.newJob(QuartzEquipCheckJob.class) //任务执行器,指定任务的实现类
.withIdentity("任务唯一标识", "任务组")
.usingJobData("参数key", "参数value")
.requestRecovery()
.build();
// 构建trigger
CronTrigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("任务唯一标识", "任务组")
// 表达式调度构建器(即任务执行的时间)
.withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?"))
.startAt(startDate) //设置触发器的开始时间。
.endAt(endDate) //设置触发器的结束时间。
.build();
// 调度容器设置JobDetail和Trigger
scheduler.scheduleJob(jobDetail, trigger);
}
/**
* 暂停job
* @param name 任务唯一标识
* @param group 任务组,唯一
* @throws SchedulerException
* @author qianguojie
* @date 2023/3/30.
*/
public void pauseJob(String name, String group) throws SchedulerException {
scheduler.pauseJob(JobKey.jobKey(name, group));
}
/**
* 恢复job
* @param name 任务唯一标识
* @param group 任务组,唯一
* @throws SchedulerException
*/
public void resumeJob(String name, String group) throws SchedulerException {
scheduler.resumeJob(JobKey.jobKey(name, group));
}
/**
* 删除job
* @param name 任务唯一标识
* @param group 任务组,唯一
* @throws SchedulerException
* @author qianguojie
* @date 2023/3/30.
*/
public void deleteJob(String name, String group) throws SchedulerException {
scheduler.deleteJob(JobKey.jobKey(name, group));
}
}
最后,记得在应用中启动Quartz的调度器,一般在主类中加上 @EnableScheduling
注解,或手动创建一个 SchedulerFactoryBean
。