导入依赖:
<dependency>
<groupId>org.quartz-schedulergroupId>
<artifactId>quartzartifactId>
<version>2.3.2version>
dependency>
定时任务-实现Job接口
public class MyJob implements Job{
@Override
public void execute(JobExecutionContext context) throws JobExecutionException{
//todo 定时任务代码逻辑
}
}
定时器工具
public class QuartzJobUtil{
private static SchedulerFactory schedulerFactory = new StdSchedulerFactory();
public static void add(String jobName, String jobGroupName, int time, Class <? extends Job> className){
//创建任务
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();
//创建触发器 每 time 秒钟执行一次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(jobName, jobGroupName)
.withSchedule(SimpleScheduleBuilder
.simpleSchedule()
.withIntervalInSeconds(time)
.repeatForever())
.build();
try {
//获取实例化的 Scheduler。
Scheduler scheduler = schedulerFactory.getScheduler();
//将任务及其触发器放入调度器
scheduler.scheduleJob(jobDetail, trigger);
//调度器开始调度任务
if (!scheduler.isShutdown()) {
scheduler.start();
//todo 启动任务
}
} catch (SchedulerException e) {
e.printStackTrace();
}
}
public void deleteJob(String jobName, String jobGroupName){
try {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.pauseTrigger(triggerKey);// 停止触发器
scheduler.unscheduleJob(triggerKey);// 移除触发器
scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));
//todo 删除任务
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
使用定时器工具添加定时任务。
由于简易,没有持久化操作,重启系统后定时任务丢失。
每个定时任务启动后会立即执行一次,需要注意。
延时启动方法:
//QuartzJobUtil.class
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(jobName, jobGroupName)
//date为Date类型参数,指到该时间后执行第一次定时任务。
.startAt(date)
.withSchedule(SimpleScheduleBuilder
.simpleSchedule()
.withIntervalInSeconds(time)
.withRepeatCount(0))
.build();
//SimpleScheduleBuilder相关API用法
//无限制次数重复定时
SimpleScheduleBuilder.repeatForever()
//限制次数重复定时,countNum为定时次数
SimpleScheduleBuilder..withRepeatCount(countNum)
//每过time时间执行一次定时任务
SimpleScheduleBuilder.withIntervalInSeconds(time)
实际上Quartz有默认的配置文件,你可以使用quartz.properties文件去设置Quartz的参数。默认的配置文件可能并不适用于大量的定时任务,因此需要根据项目需求调整quartz的参数。
工具型的写法虽然简单,但是无法使用Spring注入的变量,即使用@Autowired修饰的变量,因为是static修饰,所以需要将Spring注入的变量提前加载好。所以该写法适用于监控任务简单的场景。
建议:使用@Component修饰工具类,不使用static修饰变量与方法,统一使用Spring注入的方式调用工具类。
定时任务持久化
添加持久化池依赖:
<dependency>
<groupId>com.mchangegroupId>
<artifactId>c3p0artifactId>
<version>0.9.5.2version>
dependency>
编写配置文件quartz.properties。Quartz通过配置文件结合StdSchedulerFactory
实现载入配置,StdSchedulerFactory
默认加载工作目录下的quartz.properties
文件,读取失败时会尝试加载org/quartz包下的quartz.properties
文件。
#quartz.properties
# 实例化ThreadPool时,使用的线程类为SimpleThreadPool
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
# threadCount和threadPriority将以setter的形式注入ThreadPool实例
# 并发个数
org.quartz.threadPool.threadCount = 5
# 优先级
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
org.quartz.jobStore.misfireThreshold = 5000
#持久化使用的类
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
#数据库中表的前缀
org.quartz.jobStore.tablePrefix = QRTZ_
#数据源命名
org.quartz.jobStore.dataSource = qzDS
#qzDS 数据源
org.quartz.dataSource.qzDS.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.qzDS.URL = jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=UTF-8
org.quartz.dataSource.qzDS.user = root
org.quartz.dataSource.qzDS.password = root
org.quartz.dataSource.qzDS.maxConnections = 10
自定义配置加载,创建QuartzConfig.java
//QuartzConfig.java
import org.quartz.Scheduler;
import org.quartz.ee.servlet.QuartzInitializerListener;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import java.io.IOException;
import java.util.Properties;
/**
* Qartz配置, 搭配quartz.properties文件自定义配置, 该处目的使定时任务持久化
*/
@Configuration
public class QuartzConfig {
/**
* 读取quartz.properties 文件
* 将值初始化
* @return
*/
@Bean
public Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
/**
* 将配置文件的数据加载到SchedulerFactoryBean中
* @return
* @throws IOException
*/
@Bean
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
schedulerFactoryBean.setQuartzProperties(quartzProperties());
return schedulerFactoryBean;
}
/**
* 初始化监听器
* @return
*/
@Bean
public QuartzInitializerListener executorListener(){
return new QuartzInitializerListener();
}
/**
* 获得Scheduler 对象
* @return
* @throws IOException
*/
@Bean
public Scheduler scheduler() throws IOException {
return schedulerFactoryBean().getScheduler();
}
}
数据库创建默认表,从官网或者org/quartz/impl/jdbcjobstore包下找到对应数据库的SQL文件进行创建
DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;
CREATE TABLE QRTZ_JOB_DETAILS
(
SCHED_NAME VARCHAR(120) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
JOB_CLASS_NAME VARCHAR(250) NOT NULL,
IS_DURABLE VARCHAR(1) NOT NULL,
IS_NONCONCURRENT VARCHAR(1) NOT NULL,
IS_UPDATE_DATA VARCHAR(1) NOT NULL,
REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
);
CREATE TABLE QRTZ_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
NEXT_FIRE_TIME BIGINT(13) NULL,
PREV_FIRE_TIME BIGINT(13) NULL,
PRIORITY INTEGER NULL,
TRIGGER_STATE VARCHAR(16) NOT NULL,
TRIGGER_TYPE VARCHAR(8) NOT NULL,
START_TIME BIGINT(13) NOT NULL,
END_TIME BIGINT(13) NULL,
CALENDAR_NAME VARCHAR(200) NULL,
MISFIRE_INSTR SMALLINT(2) NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)
);
CREATE TABLE QRTZ_SIMPLE_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
REPEAT_COUNT BIGINT(7) NOT NULL,
REPEAT_INTERVAL BIGINT(12) NOT NULL,
TIMES_TRIGGERED BIGINT(10) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_CRON_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
CRON_EXPRESSION VARCHAR(200) NOT NULL,
TIME_ZONE_ID VARCHAR(80),
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_SIMPROP_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
STR_PROP_1 VARCHAR(512) NULL,
STR_PROP_2 VARCHAR(512) NULL,
STR_PROP_3 VARCHAR(512) NULL,
INT_PROP_1 INT NULL,
INT_PROP_2 INT NULL,
LONG_PROP_1 BIGINT NULL,
LONG_PROP_2 BIGINT NULL,
DEC_PROP_1 NUMERIC(13,4) NULL,
DEC_PROP_2 NUMERIC(13,4) NULL,
BOOL_PROP_1 VARCHAR(1) NULL,
BOOL_PROP_2 VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_BLOB_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
BLOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_CALENDARS
(
SCHED_NAME VARCHAR(120) NOT NULL,
CALENDAR_NAME VARCHAR(200) NOT NULL,
CALENDAR BLOB NOT NULL,
PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
);
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_FIRED_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
ENTRY_ID VARCHAR(95) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
INSTANCE_NAME VARCHAR(200) NOT NULL,
FIRED_TIME BIGINT(13) NOT NULL,
SCHED_TIME BIGINT(13) NOT NULL,
PRIORITY INTEGER NOT NULL,
STATE VARCHAR(16) NOT NULL,
JOB_NAME VARCHAR(200) NULL,
JOB_GROUP VARCHAR(200) NULL,
IS_NONCONCURRENT VARCHAR(1) NULL,
REQUESTS_RECOVERY VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,ENTRY_ID)
);
CREATE TABLE QRTZ_SCHEDULER_STATE
(
SCHED_NAME VARCHAR(120) NOT NULL,
INSTANCE_NAME VARCHAR(200) NOT NULL,
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
CHECKIN_INTERVAL BIGINT(13) NOT NULL,
PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
);
CREATE TABLE QRTZ_LOCKS
(
SCHED_NAME VARCHAR(120) NOT NULL,
LOCK_NAME VARCHAR(40) NOT NULL,
PRIMARY KEY (SCHED_NAME,LOCK_NAME)
);
commit;
解决直接实现Job接口导致@Autowired修饰的变量为空,并报空指针异常的情况。
原因:Quartz的Job时由自己管理的,因此如果想要在Job中调用Spring管理的Bean,必须让Job也加入Spring容器当中。
自定义JobFactory,使用Spring容器管理Quartz的Bean
//参考https://www.cnblogs.com/huahua035/p/7839834.html
//MyJobFactory.class
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;
/**
* Description: 自定义JobFactory,使用Spring容器管理的Quartz的Bean(Job)
*
* AdaptableJobFactory是Spring提供的SchedulerFactoryBean的默认实例化工厂,将由直接实例化Job,没有被Spring管理
*/
@Component
public class MyJobFactory extends AdaptableJobFactory {
/**
* AutowireCapableBeanFactory接口是BeanFactory的子类
* 可以连接和填充那些生命周期不被Spring管理的已存在的bean实例
* 具体请参考:http://blog.csdn.net/iycynna_123/article/details/52993542
*/
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
/**
* 创建Job实例
*
* @param bundle
* @return
* @throws Exception
*/
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
// 实例化对象
Object jobInstance = super.createJobInstance(bundle);
// 进行注入(Spring管理该Bean),这是Spring进行注入的API,可以查看Spring官方API文档
capableBeanFactory.autowireBean(jobInstance);
//返回对象
return jobInstance;
}
}
在QuartzConfig.java
配置文件中配置SchedulerFactoryBean
//QuartzConfig.java
@Autowired
private MyJobFactory myJobFactory;
@Bean //将一个方法产生为Bean并交给Spring容器管理(@Bean只能用在方法上)
public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) throws IOException {
//Spring提供SchedulerFactoryBean为Scheduler提供配置信息,并被Spring容器管理其生命周期
SchedulerFactoryBean factory = new SchedulerFactoryBean();
//启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
factory.setOverwriteExistingJobs(true);
// 延时启动(秒)
factory.setStartupDelay(20);
//设置quartz的配置文件
factory.setQuartzProperties(quartzProperties());
//设置自定义Job Factory,用于Spring管理Job bean----此处重点.
factory.setJobFactory(myJobFactory);
return factory;
}
编写Job任务
//MyJob.java
@Component
public class MyJob extends QuartzJobBean {
//使用Spring容器中的变量
@Autowired
private XxxService xxxService;
/**
* 执行Job
*
* @param jobExecutionContext
* @throws JobExecutionException
*/
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
//todo Job任务逻辑
}
以Job,Trigger,Scheduler为主要组成部分
Trigger:
SimpleTrigger:在特定的时间点,或每隔T个时间单位调度一次
CronTrigger:基于日历的调度十分有用,比如每个月,每个星期等调度方式
* * * * * * *
cron表达式,从左至右代表秒,分,时,日,月,周,年,一般情况下忽略年
维度,因此6个参数
如何在Job中增加属性?
JobFactory:
JobFactory
当trigger触发时,通过Scheduler上配置的JobFactory实例化与之关联的jobs。默认的JobFactory只是在jobs类上调用newInstance()。您可能需要创建自己的JobFactory实现,以完成诸如让应用程序的IoC或DI容器生成/初始化jobs实例之类的操作。
请参阅org.quartz.spi.JobFactory接口以及相关的Scheduler.setJobFactory(fact) 方法。
参考:
Quartz文档:w3c
第一部分内容参考:文章一