Spring整合quartz2.2.3总结,quartz动态定时任务,Quartz定时任务集群配置
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
©Copyright 蕃薯耀 2017年9月6日
http://fanshuyao.iteye.com/
一、Spring整合Quartz
使用的是spring4:4.3.9.RELEASE,Quartz2:2.2.3
二、引用Quartz 的Jar包
maven方式:(Spring不说了)
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>${quartz.version}</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz-jobs</artifactId> <version>${quartz.version}</version> </dependency>
三、在数据库创建Quartz 相关的表(下面的数据库为:tables_mysql_innodb.sql),先创建表,然后再执下面的索引,避免警告。(更多表见附件: dbTables.zip)
#
# 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;
四、新建一个Quartz相关的Properties文件:spring-quartz.properties,此配置为官网例子的配置
#配置见: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,在Spring.xml配置
<bean id="customJobFactory" class="cn.imovie.manage.task.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 -->
其中customJobFactory 是为了解决Spring quartz 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;
}
}
六、Quartz定时任务主代码:
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;
import cn.imovie.common.utils.CC;
import cn.imovie.common.utils.DateUtils;
import cn.imovie.common.utils.JasonUtils;
import cn.imovie.common.utils.StrUtils;
import cn.imovie.dao.SchedulerManageDao;
import cn.imovie.entity.task.ScheduleJob;
@Repository
public class SchedulerManageDaoImpl implements SchedulerManageDao{
private Logger log = LoggerFactory.getLogger(SchedulerManageDaoImpl.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);
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(CC.LOG_PREFIX + "新增Cron任务:"+JasonUtils.Object2String(scheduleJob));
}else {
// Trigger已存在,那么更新相应的定时设置
//表达式调度构建器
/*CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression());
//按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder.withMisfireHandlingInstructionDoNothing()).build();
JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
jobDetail.getJobDataMap().put("scheduleJob", scheduleJob);
//按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
log.info(CC.LOG_PREFIX + "任务"+JasonUtils.Object2String(scheduleJob)+"已经存在,更新trigger");*/
this.updateJobCron(scheduleJob);
}
}
/**
* 更新任务的时间表达式
* @param scheduleJob
*/
@Override
public void updateJobCron(ScheduleJob scheduleJob) throws Exception{
/*TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
//获取trigger,即在spring配置文件中定义的 bean id="myTrigger"
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
//表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression());
//按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder.withMisfireHandlingInstructionDoNothing()).build();
JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
jobDetail.getJobDataMap().put("scheduleJob", scheduleJob);
//按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);*/
//为什么要删除再新增呢?因为不这样,JobDetail的JobDataMap不更新。注解什么都试过了,没起作用。
this.deleteJob(scheduleJob);
this.addJobCron(scheduleJob);
log.info(CC.LOG_PREFIX + "更新Cron任务(先删除再更新):"+JasonUtils.Object2String(scheduleJob));
}
/**
* 新增任务
* @param scheduleJob
* @throws Exception
*/
@Override
@SuppressWarnings("unchecked")
public void addJobSimple(ScheduleJob scheduleJob) throws Exception{
TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
//任务触发
SimpleTrigger trigger = (SimpleTrigger) 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);
SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule();
Date triggerStartTime = new Date();
if("秒".equals(scheduleJob.getTimeType()) ||
"second".equalsIgnoreCase(scheduleJob.getTimeType())){
simpleScheduleBuilder.withIntervalInSeconds(scheduleJob.getTimeValue());
triggerStartTime = DateUtils.dateAddSeconds(triggerStartTime, scheduleJob.getTimeValue());
}else if("分".equals(scheduleJob.getTimeType()) || "分钟".equals(scheduleJob.getTimeType()) ||
"minute".equalsIgnoreCase(scheduleJob.getTimeType())){
simpleScheduleBuilder.withIntervalInMinutes(scheduleJob.getTimeValue());
triggerStartTime = DateUtils.dateAddMinutes(triggerStartTime, scheduleJob.getTimeValue());
}else if("时".equals(scheduleJob.getTimeType()) || "小时".equals(scheduleJob.getTimeType()) ||
"hour".equalsIgnoreCase(scheduleJob.getTimeType())){
simpleScheduleBuilder.withIntervalInHours(scheduleJob.getTimeValue());
triggerStartTime = DateUtils.dateAddHours(triggerStartTime, scheduleJob.getTimeValue());
}else if("天".equals(scheduleJob.getTimeType()) ||
"date".equalsIgnoreCase(scheduleJob.getTimeType())){
simpleScheduleBuilder.withIntervalInHours(scheduleJob.getTimeValue()*24);//2017-09-15修正问题,这里必须乘以24,因为设置的是小时
triggerStartTime = DateUtils.dateAddDays(triggerStartTime, scheduleJob.getTimeValue());
}
trigger = TriggerBuilder.newTrigger().withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup())
.startAt(triggerStartTime).withSchedule(simpleScheduleBuilder.repeatForever().withMisfireHandlingInstructionNextWithRemainingCount()).build();
scheduler.scheduleJob(jobDetail, trigger);
log.info(CC.LOG_PREFIX + "新增简单任务:"+JasonUtils.Object2String(scheduleJob));
}else {
this.updateJobCron(scheduleJob);
}
}
/**
* 更新任务的时间表达式
* @param scheduleJob
* @throws Exception
*/
@Override
public void updateJobSimple(ScheduleJob scheduleJob) throws Exception{
//为什么要删除再新增呢?因为不这样,JobDetail的JobDataMap不更新。注解什么都试过了,没起作用。
this.deleteJob(scheduleJob);
this.addJobSimple(scheduleJob);
log.info(CC.LOG_PREFIX + "更新简单任务(先删除再更新):"+JasonUtils.Object2String(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(CC.LOG_PREFIX + "暂停任务:"+JasonUtils.Object2String(scheduleJob));
}
/**
* 暂停全部任务
* @throws SchedulerException
*/
@Override
public void pauseAll() throws Exception{
scheduler.pauseAll();
log.info(CC.LOG_PREFIX + "暂停所有任务");
}
/**
* 恢复任务
* @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(CC.LOG_PREFIX + "恢复任务:"+JasonUtils.Object2String(scheduleJob));
}
/**
* 恢复所有任务
* @throws Exception
*/
@Override
public void resumeAll() throws Exception{
scheduler.resumeAll();
log.info(CC.LOG_PREFIX + "恢复所有任务");
}
/**
* 删除任务后,所对应的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(CC.LOG_PREFIX + "删除任务:"+JasonUtils.Object2String(scheduleJob));
}
/**
* 立即运行任务
* @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(CC.LOG_PREFIX + "运行任务:"+JasonUtils.Object2String(scheduleJob));
}
/**
* 获取quartz调度器的计划任务
* @return
*/
@Override
public List<ScheduleJob> getScheduleJobList(){
List<ScheduleJob> jobList = null;
try {
GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
jobList = new ArrayList<ScheduleJob>();
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.setClazz(jobKey.getClass().toString());
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;
}
/**
* 获取quartz调度器的运行任务
* @return
*/
@Override
public List<ScheduleJob> getScheduleJobRunningList(){
List<ScheduleJob> jobList = null;
try {
List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
jobList = new ArrayList<ScheduleJob>(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(jobKey.getClass().toString());
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;
}
}
SchedulerManageDao接口:
import java.util.List;
import cn.imovie.entity.task.ScheduleJob;
public interface SchedulerManageDao {
/**
* 新增任务
* @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<ScheduleJob> getScheduleJobList();
/**
* 获取quartz调度器的运行任务
* @return
*/
public List<ScheduleJob> 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;
}
七、自定义一张表,用来保存设置定时任务的时间等信息,方便取出来显示
因为Quartz定时任务设置的时间都是转为毫秒后保存的,所以当你需要将设置当时的具体时间取出来显示是还原不了的,所以创建一张自定义表保存定时任务的信息。
表主要是分为表达式和简单的时间配置2种,定时任务优化判断cron_expression是否为空,如果不为空,优先使用表达式来生成动态定时任务,如果为空,则通过获取time_value、time_type来设置定时任务。
表结构(Mysql)如下:
CREATE TABLE schedule_job(
schedule_job_id BIGINT PRIMARY KEY COMMENT 'ID主键' ,
job_name VARCHAR(200) NOT NULL COMMENT '任务名称',
job_group VARCHAR(200) NOT NULL COMMENT '任务分组',
clazz VARCHAR(500) NOT NULL COMMENT '定时任务对应的类(包括包路径)',
job_status VARCHAR(2) NOT NULL COMMENT '任务状态 1禁用 2启用',
cron_expression VARCHAR(200) COMMENT '任务运行时间表达式',
time_value INT COMMENT '简单时间格式的值',
time_type VARCHAR(50) COMMENT '简单时间格式的类型:天、时、分、秒',
job_desc VARCHAR(500) COMMENT '任务描述',
create_man BIGINT NOT NULL,
create_time DATETIME NOT NULL,
update_man BIGINT,
update_time DATETIME
);
对应的类(ScheduleJob)如下:
import java.io.Serializable;
import java.util.Date;
import com.dexcoder.dal.annotation.Table;
import com.dexcoder.dal.annotation.Transient;
@SuppressWarnings("serial")
@Table(name = "schedule_job", pkField = "scheduleJobId", pkColumn = "schedule_job_id")
public class ScheduleJob implements Serializable{
private Long scheduleJobId;
/** 任务名称 */
private String jobName;
/** 任务分组 */
private String jobGroup;
/** 定时任务对应的类(包括包路径),如:cn.imovie.manage.task.job.TicketMoneyLessThanNormalWarn */
private String clazz;
/** 任务状态:1禁用 2启用*/
private String jobStatus;
/** 任务运行时间表达式 */
private String cronExpression;
/** 简单的时间值 */
private Integer timeValue;
/** 时间类型:秒、分、小时、天 */
private String timeType;
/** 任务描述 */
private String jobDesc;
private Long createMan;
private Date createTime;
private Long updateMan;
private Date updateTime;
// 非持久化属性
private String createManText;
private String updateManText;
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;
}
public Long getCreateMan() {
return createMan;
}
public void setCreateMan(Long createMan) {
this.createMan = createMan;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Long getUpdateMan() {
return updateMan;
}
public void setUpdateMan(Long updateMan) {
this.updateMan = updateMan;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
@Transient
public String getCreateManText() {
return createManText;
}
public void setCreateManText(String createManText) {
this.createManText = createManText;
}
@Transient
public String getUpdateManText() {
return updateManText;
}
public void setUpdateManText(String updateManText) {
this.updateManText = updateManText;
}
}
八、一个定时任务Job的例子(仅供参考):这里直接使用了service的注入,默认是不可以的,需要配置customJobFactory ,上面已经有说明。
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.PersistJobDataAfterExecution;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import cn.imovie.common.utils.CC;
import cn.imovie.common.utils.StrUtils;
import cn.imovie.entity.TsCinemaBasePriceLimit;
import cn.imovie.entity.warn.Warning;
import cn.imovie.manage.enums.WarnType;
import cn.imovie.service.TsCinemaBasePriceLimitService;
import cn.imovie.service.WarningService;
@Component
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class CinemaSalePriceGreaterThanOtherPlatformJob implements Job{
private Logger log = LoggerFactory.getLogger(CinemaSalePriceGreaterThanOtherPlatformJob.class);
@Autowired
private TsCinemaBasePriceLimitService tsCinemaBasePriceLimitService;
@Autowired
private WarningService warningService;
@Override
public void execute(JobExecutionContext context)
throws JobExecutionException {
Date currentTime = new Date();
Map<String, List<TsCinemaBasePriceLimit>> map = new HashMap<String, List<TsCinemaBasePriceLimit>>();
try {
map = tsCinemaBasePriceLimitService.listCinemaSalePriceGreaterThanOtherPlatform("1,3", currentTime);
} catch (Exception e) {
e.printStackTrace();
}
if(!StrUtils.isEmptyMap(map)){
List<TsCinemaBasePriceLimit> list_2d = map.get("2d");
String reason = "2D或3D销售价格高于其它平台的价格设置";
for (TsCinemaBasePriceLimit tsCinemaBasePriceLimit : list_2d) {
Warning warning = new Warning();
warning.setWarnType(WarnType.CINEMA_SALE_PRICE_GREATER_THAN_OTHER_PLATFORM.getValue());
warning.setAssociatedTable("ts_cinema_base_price_limit");
warning.setAssociatedTableId(tsCinemaBasePriceLimit.getPriceLimitId());
warning.setReason(reason);
warning.setCreateTime(currentTime);
warning.setCreateMan(-999L);
warningService.save(warning);
}
List<TsCinemaBasePriceLimit> list_3d = map.get("3d");
for (TsCinemaBasePriceLimit tsCinemaBasePriceLimit_3d : list_3d) {
Warning warning = new Warning();
warning.setWarnType(WarnType.CINEMA_SALE_PRICE_GREATER_THAN_OTHER_PLATFORM.getValue());
warning.setAssociatedTable("ts_cinema_base_price_limit");
warning.setAssociatedTableId(tsCinemaBasePriceLimit_3d.getPriceLimitId());
warning.setReason(reason);
warning.setCreateTime(currentTime);
warning.setCreateMan(-999L);
warningService.save(warning);
}
}
log.info(CC.LOG_PREFIX + "[CinemaSalePriceGreaterThanOtherPlatformJob]定时任务执行完毕。");
}
}
(如果你觉得文章对你有帮助,欢迎捐赠,^_^,谢谢!)
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
©Copyright 蕃薯耀 2017年9月6日
http://fanshuyao.iteye.com/