由于是集群模式下实现定时任务,Quartz内部是通过使用数据库来作为媒介,进行消息的通知,因为所有的机器会操作同一个库,这样不会造成定时任务的混乱。
org.springframework
spring-context
4.3.18.RELEASE
org.quartz-scheduler
quartz
2.2.1
org.quartz-scheduler
quartz-jobs
2.2.1
mysql
mysql-connector-java
5.1.36
这个数据库的DDL语句Quartz官方有给出,根据你所使用的数据库来选择对应的DDL
点击查看
我选择的MYSQL数据库,
注意
使用mysql一定要切换成innodb引擎、
下面给出对应的建表语句,一定要先执行建表语句,再执行创建索引的语句,不然就会产生错误。
#
# In your Quartz properties file, you'll need to set
# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#
#
# By: Ron Cordell - roncordell
# I didn't see this anywhere, so I thought I'd post it here. This is the script from Quartz to create the tables in a MySQL database, modified to use INNODB instead of MYISAM.
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;
一般情况下,可以直接在存放资源文件的目录下建立spring-quartz.properties属性文件,用于存放quartz的相关配置,如果使用的idea开发,直接放在resources文件夹目录下即可,该目录对应的就是classpath,可以很方便的索引到文件。
#配置见http://www.quartz-scheduler.org/documentation/quartz-2.2.x/configuration/ConfigJDBCJobStoreClustering.html
#=====================================================================
#Configure Main Scheduler Properties
#============================================================================
org.quartz.scheduler.instanceName = MyClusteredScheduler
org.quartz.scheduler.instanceId = AUTO
#============================================================================
#Configure ThreadPool
#============================================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 25
org.quartz.threadPool.threadPriority = 5
#======================================================================
#Configure JobStore
#======================================================================
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.useProperties = false
org.quartz.jobStore.dataSource = myDS
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000
为了解决Spring quartz Job不能依赖注入。需要自定义job工厂类
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
public class CustomJobFactory extends SpringBeanJobFactory{
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
//进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
spirng-quartz.xml
<!--这里定义你自己的包的全限定名-->
<bean id="customJobFactory" class="xx.xx.xx.job.CustomJobFactory"></bean>
<!-- 定时任务配置 start -->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<!-- 可选,QuartzScheduler 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 -->
<property name="overwriteExistingJobs" value="true" />
<!-- 必须的,QuartzScheduler 延时启动,应用启动完后 QuartzScheduler 再启动 -->
<property name="startupDelay" value="2" />
<!-- 设置自动启动 -->
<property name="autoStartup" value="true" />
<property name="jobFactory" ref="customJobFactory"></property>
<property name="applicationContextSchedulerContextKey" value="applicationContextKey" />
<property name="configLocation" value="classpath:spring-quartz.properties" />
</bean>
<!-- 定时任务配置 end -->
为了方便解耦,面向接口编程,先定义一个SchedulerManage
接口,具体实现SchedulerManageImpl
。
ScheduleJob
封装一些定时任务需要的信息
import java.io.Serializable;
import java.util.Date;
@SuppressWarnings("serial")
public class ScheduleJob implements Serializable{
private Long scheduleJobId;
/** 任务名称 */
private String jobName;
/** 任务分组 */
private String jobGroup;
/** 定时任务对应的类(包括包路径) */
private String clazz;
/** 任务状态:1禁用 2启用*/
private String jobStatus;
/** 任务运行时间表达式 */
private String cronExpression;
/** 简单的时间值 */
private Integer timeValue;
/** 时间类型:秒、分、小时、天 */
private String timeType;
/** 任务描述 */
private String jobDesc;
public Long getScheduleJobId() {
return scheduleJobId;
}
public void setScheduleJobId(Long scheduleJobId) {
this.scheduleJobId = scheduleJobId;
}
public String getJobName() {
return jobName;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
public String getJobGroup() {
return jobGroup;
}
public void setJobGroup(String jobGroup) {
this.jobGroup = jobGroup;
}
public String getClazz() {
return clazz;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
public String getJobStatus() {
return jobStatus;
}
public void setJobStatus(String jobStatus) {
this.jobStatus = jobStatus;
}
public String getCronExpression() {
return cronExpression;
}
public void setCronExpression(String cronExpression) {
this.cronExpression = cronExpression;
}
public Integer getTimeValue() {
return timeValue;
}
public void setTimeValue(Integer timeValue) {
this.timeValue = timeValue;
}
public String getTimeType() {
return timeType;
}
public void setTimeType(String timeType) {
this.timeType = timeType;
}
public String getJobDesc() {
return jobDesc;
}
public void setJobDesc(String jobDesc) {
this.jobDesc = jobDesc;
}
}
SchedulerManage
import java.util.List;
public interface SchedulerManage {
/**
* 新增任务
* @param scheduleJob
* @throws Exception
*/
public void addJobCron(ScheduleJob scheduleJob) throws Exception;
/**
* 暂停任务
* @param scheduleJob
*/
public void pauseJob(ScheduleJob scheduleJob) throws Exception;
/**
* 暂停全部任务
*/
public void pauseAll() throws Exception;
/**
* 恢复任务
* @param scheduleJob
*/
public void resumeJob(ScheduleJob scheduleJob) throws Exception;
/**
* 恢复所有任务
*/
public void resumeAll() throws Exception;
/**
* 删除任务后,所对应的trigger也将被删除
* @param scheduleJob
*/
public void deleteJob(ScheduleJob scheduleJob) throws Exception;
/**
* 立即运行任务
* @param scheduleJob
*/
public void triggerJob(ScheduleJob scheduleJob) throws Exception;
/**
* 更新任务的时间表达式
* @param scheduleJob
*/
public void updateJobCron(ScheduleJob scheduleJob) throws Exception;
/**
* 获取quartz调度器的计划任务
* @return
*/
public List getScheduleJobList();
/**
* 获取quartz调度器的运行任务
* @return
*/
public List getScheduleJobRunningList();
public void addJobSimple(ScheduleJob scheduleJob) throws Exception;
public void updateJobSimple(ScheduleJob scheduleJob) throws Exception;
/**
* 如果scheduleJob.getCronExpression()表达式不为空,使用表达式方式,如果为空,则使用简单方式
* @param scheduleJob
*/
public void add(ScheduleJob scheduleJob) throws Exception;
/**
* 如果scheduleJob.getCronExpression()表达式不为空,使用表达式方式,如果为空,则使用简单方式
* @param scheduleJob
*/
public void update(ScheduleJob scheduleJob) throws Exception;
SchedulerManageImpl
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository
public class SchedulerManageImpl implements SchedulerManage{
private Logger log = LoggerFactory.getLogger(SchedulerManageImpl.class);
@Autowired
private Scheduler scheduler;
/**
* 新增任务
* @param scheduleJob
*/
@Override
public void add(ScheduleJob scheduleJob) throws Exception{
if(!StrUtils.isBlank(scheduleJob.getCronExpression())){
this.addJobCron(scheduleJob);
}else{
this.addJobSimple(scheduleJob);
}
}
/**
* 更新任务
* @param scheduleJob
*/
@Override
public void update(ScheduleJob scheduleJob) throws Exception{
if(!StrUtils.isBlank(scheduleJob.getCronExpression())){
this.updateJobCron(scheduleJob);
}else{
this.updateJobSimple(scheduleJob);
}
}
/**
* 新增任务
* @param scheduleJob
* @throws Exception
*/
@SuppressWarnings("unchecked")
@Override
public void addJobCron(ScheduleJob scheduleJob) throws Exception{
TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
//任务触发
Trigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
if (null == trigger) {
JobDetail jobDetail = JobBuilder.newJob((Class extends Job>) Class.forName(scheduleJob.getClazz()))
.withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup()).build();
jobDetail.getJobDataMap().put("scheduleJob", scheduleJob);
//这里需要纪录class方便,后续的反射调用
jobDetail.getJobDataMap().put("class", scheduleJob.getClazz());
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression());
/*withMisfireHandlingInstructionDoNothing
——不触发立即执行
——等待下次Cron触发频率到达时刻开始按照Cron频率依次执行
withMisfireHandlingInstructionIgnoreMisfires
——以错过的第一个频率时间立刻开始执行
——重做错过的所有频率周期后
——当下一次触发频率发生时间大于当前时间后,再按照正常的Cron频率依次执行
withMisfireHandlingInstructionFireAndProceed
——以当前时间为触发频率立刻触发一次执行
——然后按照Cron频率依次执行*/
trigger = TriggerBuilder.newTrigger().withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup()).withSchedule(cronScheduleBuilder.withMisfireHandlingInstructionDoNothing()).build();
scheduler.scheduleJob(jobDetail, trigger);
log.info("新增Cron任务:"+scheduleJob.toString());
}else {
// Trigger已存在,那么更新相应的定时设置
this.updateJobCron(scheduleJob);
}
}
/**
* 更新任务的时间表达式
* @param scheduleJob
*/
@Override
public void updateJobCron(ScheduleJob scheduleJob) throws Exception{
this.deleteJob(scheduleJob);
this.addJobCron(scheduleJob);
log.info( "更新Cron任务(先删除再更新):"scheduleJob.toString());
}
/**
* 新增任务
* @param scheduleJob
* @throws Exception
*/
@Override
@SuppressWarnings("unchecked")
public void addJobSimple(ScheduleJob scheduleJob) throws Exception{
//暂时没有使用到simple,一般都是使用cron表达式
}
/**
* 更新任务的时间表达式
* @param scheduleJob
* @throws Exception
*/
@Override
public void updateJobSimple(ScheduleJob scheduleJob) throws Exception{
// this.deleteJob(scheduleJob);
// this.addJobSimple(scheduleJob);
}
/**
* 暂停任务
* @param scheduleJob
* @throws Exception
*/
@Override
public void pauseJob(ScheduleJob scheduleJob) throws Exception{
JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
scheduler.pauseJob(jobKey);
log.info( "暂停任务:"+scheduleJob.toString());
}
/**
* 暂停全部任务
* @throws SchedulerException
*/
@Override
public void pauseAll() throws Exception{
scheduler.pauseAll();
log.info("暂停所有任务");
}
/**
* 恢复任务
* @param scheduleJob
* @throws Exception
*/
@Override
public void resumeJob(ScheduleJob scheduleJob) throws Exception{
JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
scheduler.resumeJob(jobKey);
log.info( "恢复任务:"+scheduleJob.toString());
}
/**
* 恢复所有任务
* @throws Exception
*/
@Override
public void resumeAll() throws Exception{
scheduler.resumeAll();
log.info("恢复所有任务");
}
/**
* 删除任务后,所对应的trigger也将被删除
* @param scheduleJob
* @throws Exception
*/
@Override
public void deleteJob(ScheduleJob scheduleJob) throws Exception{
JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
scheduler.pauseJob(jobKey);//先暂停任务
scheduler.deleteJob(jobKey);//再删除任务
log.info( "删除任务:"+scheduleJob.toString());
}
/**
* 立即运行任务
* @param scheduleJob
* @throws Exception
*/
@Override
public void triggerJob(ScheduleJob scheduleJob) throws Exception{
JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
scheduler.triggerJob(jobKey);
log.info("运行任务:"+scheduleJob.toString());
}
/**
* 获取quartz调度器的计划任务
* @return
*/
@Override
public List getScheduleJobList(){
List jobList = null;
try {
GroupMatcher matcher = GroupMatcher.anyJobGroup();
Set jobKeys = scheduler.getJobKeys(matcher);
jobList = new ArrayList();
for (JobKey jobKey : jobKeys) {
List extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
for (Trigger trigger : triggers) {
ScheduleJob job = new ScheduleJob();
job.setJobName(jobKey.getName());
job.setJobGroup(jobKey.getGroup());
job.setJobDesc("触发器:" + trigger.getKey());
Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
job.setJobStatus(triggerState.name());
job.setClazz(jobKey.getClass().toString());
if (trigger instanceof CronTrigger) {
CronTrigger cronTrigger = (CronTrigger) trigger;
String cronExpression = cronTrigger.getCronExpression();
job.setCronExpression(cronExpression);
}else if(trigger instanceof SimpleTrigger){
SimpleTrigger simpleTrigger = (SimpleTrigger) trigger;
long milliseconds = simpleTrigger.getRepeatInterval();
job.setTimeValue((int) (milliseconds/1000));
}
jobList.add(job);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return jobList;
}
/**
* 获取quartz调度器的运行任务
* @return
*/
@Override
public List getScheduleJobRunningList(){
List jobList = null;
try {
List executingJobs = scheduler.getCurrentlyExecutingJobs();
jobList = new ArrayList(executingJobs.size());
for (JobExecutionContext executingJob : executingJobs) {
ScheduleJob job = new ScheduleJob();
JobDetail jobDetail = executingJob.getJobDetail();
JobKey jobKey = jobDetail.getKey();
Trigger trigger = executingJob.getTrigger();
job.setJobName(jobKey.getName());
job.setJobGroup(jobKey.getGroup());
job.setClazz(jobDetail.getJobDataMap.get("class"));
job.setJobDesc("触发器:" + trigger.getKey());
Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
job.setJobStatus(triggerState.name());
if (trigger instanceof CronTrigger) {
CronTrigger cronTrigger = (CronTrigger) trigger;
String cronExpression = cronTrigger.getCronExpression();
job.setCronExpression(cronExpression);
}else if(trigger instanceof SimpleTrigger){
SimpleTrigger simpleTrigger = (SimpleTrigger) trigger;
long milliseconds = simpleTrigger.getRepeatInterval();
job.setTimeValue((int) (milliseconds/1000));
}
jobList.add(job);
}
} catch (Exception e) {
e.printStackTrace();
}
return jobList;
}
}
java.io.NotSerializableException: Unable to serialize JobDataMap for insertion into database because the value of property 'methodInvoker' is not serializable: org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean
解决办法:地址,上面有解决的MethodInvokingJobDetailFactoryBean代码。
但是我又看spirng官方给出的说明:
NOTE: JobDetails created via this FactoryBean are not serializable and thus not suitable for persistent job stores. You need to implement your own Quartz Job as a thin wrapper for each case where you want a persistent job to delegate to a specific service method.
Compatible with Quartz 1.5+ as well as Quartz 2.0-2.2, as of Spring 3.2.
使用MethodInvokingJobDetailFactoryBean工厂类创建的JobDetail是无法被序列化的,这就意味着无法进行持久化操作,所以建议还是自己手动创建一个Job类的实现Job,Serializable
接口。
没有给job添加触发器,你可以在配置文件中加上durable属性即可。// durable, 指明任务就算没有绑定Trigger仍保留在Quartz的JobStore中.
解决办法:
org.quartz.JobPersistenceException: The job (DEFAULT.studyDetail) referenced by the trigger does not exist.
原因一般是数据源配置导致的问题。
可能的原因是:数据源未配置成自动提交,当第一次启动trigger时,之前对数据库的job的增加的事物没有自动提交,导致后面的事物无法查询到。
如果数据源是通过dbcp配置的将自动提交配置为true
终于搞定了,Quartz的集群基本上就是这些问题了,今天折腾了一上午,看了下百度,google上面的基本上不怎么全,有些地方都写的不怎么完整,还是自己结合网上的解释然后根据源码大致总结了这些,希望能够用得到。