蕃薯耀 阅读(12) 评论(0)

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());
		    	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/