本次我们集成Quartz定时任务。
1、引入依赖
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
2、创建quartz.properties文件
# 固定前缀org.quartz
org.quartz.scheduler.instanceName = DefaultQuartzScheduler
org.quartz.scheduler.instanceId = AUTO
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false
# 实例化ThreadPool时,使用的线程类为SimpleThreadPool
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
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.clusterCheckinInterval = 15000
org.quartz.jobStore.isClustered = true
3、创建配置文件
package com.streamyear.course.config;
import com.streamyear.course.common.service.JobFactory;
import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
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 javax.sql.DataSource;
import java.io.IOException;
@Configuration
public class SchedulerConfiguration {
@Autowired
private DataSource dataSource;
@Autowired
private JobFactory 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.setDataSource(dataSource);
factory.setJobFactory(jobFactory);
return factory;
}
/*
* 通过SchedulerFactoryBean获取Scheduler的实例
*/
@Bean(name = "scheduler")
public Scheduler scheduler() throws IOException {
return schedulerFactoryBean().getScheduler();
}
}
package com.streamyear.course.common.service;
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;
/**
* 解决在spring中无法自动注入的问题
*/
@Component
public class JobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
//进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
4、创建工具类
package com.streamyear.course.common.service;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.JobKey.jobKey;
import static org.quartz.TriggerBuilder.newTrigger;
import static org.quartz.TriggerKey.triggerKey;
@Component
public class QuartzService {
private String JOB_NAME = "JOB_NAME_API";
private String JOB_GROUP_NAME = "JOB_GROUP_NAME_API";
private String TRIGGER_NAME = "TRIGGER_NAME_API";
private String TRIGGER_GROUP_NAME = "TRIGGER_GROUP_NAME_API";
/**
* 注入调度器
*/
@Autowired
private Scheduler scheduler;
/**
* @Description: 添加一个定时任务,使用默认的任务组名,触发器名,触发器组名
* @param jobClass:任务
* @param time:时间设置,CronExpression表达式
*/
public void addJob(@SuppressWarnings("rawtypes") Class jobClass, String time) {
addJob(jobClass,time,JOB_NAME,JOB_GROUP_NAME,TRIGGER_NAME,TRIGGER_GROUP_NAME);
}
/**
* @Description: 添加一个定时任务
* @param jobClass:任务
* @param time:时间设置,CronExpression表达式
* @param jobName:任务名
* @param jobGroupName:任务组名
* @param triggerName:触发器名
* @param triggerGroupName:触发器组名
*/
public void addJob(@SuppressWarnings("rawtypes") Class jobClass, String time,
String jobName, String jobGroupName, String triggerName, String triggerGroupName) {
JobDetail job = newJob(jobClass).withIdentity(jobName, jobGroupName).build();
CronTrigger trigger = newTrigger().withIdentity(triggerName, triggerGroupName)
.withSchedule(cronSchedule(time)).build();
try {
// 返回为 null 添加失败
Date ft = scheduler.scheduleJob(job, trigger);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description: 定义一个任务之后进行触发设定(使用默认的任务组名,触发器名,触发器组名)
* @param time
*/
@SuppressWarnings("rawtypes")
public void addJObLaterUse(@SuppressWarnings("rawtypes") Class jobClass, String time) {
addJObLaterUse(jobClass,time,JOB_NAME,JOB_GROUP_NAME);
}
/**
* @Description: 定义一个任务之后进行触发设定
* @param time
* @param jobName:任务名
* @param jobGroupName:任务组名
*/
@SuppressWarnings("rawtypes")
public void addJObLaterUse(@SuppressWarnings("rawtypes") Class jobClass, String time,
String jobName,String jobGroupName) {
JobDetail job = newJob(jobClass).withIdentity(jobName, jobGroupName).storeDurably().build();
try {
scheduler.addJob(job, false);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description: 对已存储的任务进行scheduling(使用默认的任务组名,触发器名,触发器组名)
* @param time
*/
@SuppressWarnings("rawtypes")
public void schedulingStoredJOb(@SuppressWarnings("rawtypes") Class jobClass, String time) {
schedulingStoredJOb(jobClass,time,JOB_NAME,JOB_GROUP_NAME,TRIGGER_NAME,TRIGGER_GROUP_NAME);
}
/**
* @Description: 对已存储的任务进行scheduling
* @param time
* @param jobName:任务名
* @param jobGroupName:任务组名
*/
@SuppressWarnings("rawtypes")
public void schedulingStoredJOb(@SuppressWarnings("rawtypes") Class jobClass, String time,
String jobName,String jobGroupName,String triggerName, String triggerGroupName) {
Trigger trigger = newTrigger().withIdentity(triggerName, triggerGroupName).startNow()
.forJob(jobKey(jobName,jobGroupName))
.build();
try {
scheduler.scheduleJob(trigger);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description: 修改一个任务的触发时间(使用默认的任务组名,触发器名,触发器组名)
* @param time
*/
@SuppressWarnings("rawtypes")
public void modifyJobTime(String time) {
modifyJobTime(TRIGGER_NAME, TRIGGER_GROUP_NAME, time);
}
/**
* @Description: 修改一个任务的触发时间
* @param triggerName
* @param triggerGroupName
* @param time
*/
public void modifyJobTime(String triggerName, String triggerGroupName, String time) {
Trigger trigger = newTrigger().withIdentity(triggerName, triggerGroupName).withSchedule(cronSchedule(time)).startNow().build();
try {
scheduler.rescheduleJob(triggerKey(triggerName, triggerGroupName), trigger);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description: 修改一个任务(使用默认的任务组名,任务名)
*/
@SuppressWarnings("rawtypes")
public void modifyJob(@SuppressWarnings("rawtypes") Class jobClass) {
modifyJob(jobClass,JOB_NAME,JOB_GROUP_NAME);
}
/**
* @Description: 修改一个任务
* @param jobName:任务名
* @param jobGroupName:任务组名
*/
public void modifyJob(@SuppressWarnings("rawtypes") Class jobClass, String jobName,String jobGroupName) {
JobDetail job1 = newJob(jobClass).withIdentity(jobName,jobGroupName).build();
try {
scheduler.addJob(job1, true);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description: 删除一个任务的的trigger
* @param triggerName
* @param triggerGroupName
*/
public void unschedulingJob(String triggerName, String triggerGroupName) {
try {
scheduler.unscheduleJob(triggerKey(triggerName,triggerGroupName));
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description: 移除一个任务,以及任务的所有trigger
* @param jobName
*/
public void removeJob(String jobName,String jobGroupName) {
try {
scheduler.deleteJob(jobKey(jobName,jobGroupName));
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description:启动所有定时任务
*/
public void startJobs() {
try {
scheduler.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description:关闭所有定时任务
*/
public void shutdownJobs() {
try {
if (!scheduler.isShutdown()) {
//未传参或false:不等待执行完成便结束;true:等待任务执行完才结束
scheduler.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
5、创建quartz的相关表
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
)
) ENGINE = INNODB;
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
)
) ENGINE = INNODB;
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
)
) ENGINE = INNODB;
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 (120) 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
)
) ENGINE = INNODB;
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
)
) ENGINE = INNODB;
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
),
INDEX (
SCHED_NAME,
TRIGGER_NAME,
TRIGGER_GROUP
),
FOREIGN KEY (
SCHED_NAME,
TRIGGER_NAME,
TRIGGER_GROUP
) REFERENCES QRTZ_TRIGGERS (
SCHED_NAME,
TRIGGER_NAME,
TRIGGER_GROUP
)
) ENGINE = INNODB;
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)
) ENGINE = INNODB;
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
SCHED_NAME VARCHAR (120) NOT NULL,
TRIGGER_GROUP VARCHAR (200) NOT NULL,
PRIMARY KEY (SCHED_NAME, TRIGGER_GROUP)
) ENGINE = INNODB;
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)
) ENGINE = INNODB;
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)
) ENGINE = INNODB;
CREATE TABLE QRTZ_LOCKS (
SCHED_NAME VARCHAR (120) NOT NULL,
LOCK_NAME VARCHAR (40) NOT NULL,
PRIMARY KEY (SCHED_NAME, LOCK_NAME)
) ENGINE = INNODB;
CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS (
SCHED_NAME,
REQUESTS_RECOVERY
);
CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS (SCHED_NAME, JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS (
SCHED_NAME,
JOB_NAME,
JOB_GROUP
);
CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS (SCHED_NAME, JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS (SCHED_NAME, CALENDAR_NAME);
CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS (
SCHED_NAME,
TRIGGER_NAME,
TRIGGER_GROUP,
TRIGGER_STATE
);
CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS (
SCHED_NAME,
TRIGGER_GROUP,
TRIGGER_STATE
);
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS (SCHED_NAME, NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS (
SCHED_NAME,
TRIGGER_STATE,
NEXT_FIRE_TIME
);
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS (
SCHED_NAME,
MISFIRE_INSTR,
NEXT_FIRE_TIME
);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS (
SCHED_NAME,
MISFIRE_INSTR,
NEXT_FIRE_TIME,
TRIGGER_STATE
);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS (
SCHED_NAME,
MISFIRE_INSTR,
NEXT_FIRE_TIME,
TRIGGER_GROUP,
TRIGGER_STATE
);
CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME);
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS (
SCHED_NAME,
INSTANCE_NAME,
REQUESTS_RECOVERY
);
CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS (
SCHED_NAME,
JOB_NAME,
JOB_GROUP
);
CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS (
SCHED_NAME,
TRIGGER_NAME,
TRIGGER_GROUP
);
CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);
COMMIT;
6、准备测试
@Autowired
private QuartzService quartzService;
@RequestMapping("quartz")
public String quartz() throws Exception {
quartzService.addJob(TestJob.class,"0/5 * * * * ?");
return "ok";
}
package com.streamyear.course.job;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.Date;
public class TestJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
Date fireTime = jobExecutionContext.getFireTime();
System.out.println("执行定时任务的时间为: " + fireTime);
}
}