quartz的使用比较普遍,动态修改修改也比较成型,这里只列举自己在项目中已比较简单的方式来实现的quartz的动态修改。
首先把所有quartz任务定义放入放入数据库中,对应java自定义实体如下
public class SchedulerJob {
public static final int STATUS_USED = 1; //可用状态
/** 任务id spring的bean名称*/
private String jobId;
/** 任务名称 */
private String jobName;
/** 任务状态 0停用 1启用 */
private Integer jobStatus;
/** 任务运行时间表达式 */
private String cronExpression;
对应定义任务运行的接口定义
/**
*
* @ClassName: SchedulerJobBean
* @Description: 定时任务Bean的顶级接口
* @Create In 2014年9月23日 By lee
*/
public interface SchedulerJobBean {
/**
* 定时任务执行业务逻辑方法体
* @Methods Name execute
* @Create In 2014年9月23日 By lee
* @param context
*/
public void execute(JobExecutionContext context);
}
SchedulerJob中的jobId即是SchedulerJobBean实现的spring bean id,因此所有定时任务需实现SchedulerJobBean接口。
然后自定义一个quartz运行工厂类,来执行定时任务实现
/**
* 单机任务执行工厂
* @ClassName: SingleQuartzJobFactory
* @Description: TODO
* @Create In 2015年1月14日 By lee
*/
@DisallowConcurrentExecution
public class SingleQuartzJobFactory implements Job {
private static final Logger log = LoggerFactory.getLogger(SingleQuartzJobFactory.class);
public void execute(JobExecutionContext context) throws JobExecutionException {
SchedulerJob scheduleJob = (SchedulerJob)context.getMergedJobDataMap().get("scheduleJob");
try{
SchedulerJobBean jobBean = (SchedulerJobBean) ContextHolder.getBean(scheduleJob.getJobId());
jobBean.execute(context);
} catch (Exception ex){
log.error("====================Scheduler-error-begin====================");
log.error(ex.toString());
StackTraceElement[] element = ex.getStackTrace();
for(int i=0;i<element.length;i++){
log.error("位置:"+element[i]);
}
log.error("====================Scheduler-error-end====================");
}
}
}
最后需要一个加载器来实现加载功能,这里我封装了一个manager来处理。由于为集群情况考虑,先封装了一个基类管理器(其中关于集群部分下篇介绍)
/**
* quartz任务管理器基类
* @ClassName: AbstractQuartzManager
* @Description: TODO
* @Create In 2015年1月14日 By lee
*/
public abstract class AbstractQuartzManager {
private static final Logger log = LoggerFactory.getLogger(AbstractQuartzManager.class);
private static String schedulerState = ""; //定任务状态(single单机状态、cluster集群状态、null未启动状态)
public static final String STATE_SINGLE = "single"; //单机状态
public static final String STATE_CLUSTER = "cluster"; //集群状态
public static final String STATE_NULL = "null"; //未启动状态
/**
* 更新定时任务
* @Methods Name update
* @Create In 2014年9月23日 By lee
* @param job
* @throws SchedulerException
*/
public static void update(SchedulerJob oldJob, SchedulerJob newJob) throws SchedulerException{
if(oldJob==null){
if(SchedulerJob.STATUS_USED==newJob.getJobStatus()){
create(newJob);
}
}else{
SchedulerFactoryBean schedulerFactoryBean = ContextHolder.getBean(SchedulerFactoryBean.class);
Scheduler scheduler = schedulerFactoryBean.getScheduler();
//获取触发器标识
TriggerKey triggerKey = TriggerKey.triggerKey(oldJob.getJobId(), SchedulerJob.JOB_GOURP);
//获取触发器trigger
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
if(null!=trigger){//如果已存在任务
delete(oldJob);
}
if(SchedulerJob.STATUS_USED==newJob.getJobStatus()){
create(newJob);
}
}
}
public static void update(SchedulerJob job) throws SchedulerException{
if(job!=null){
SchedulerFactoryBean schedulerFactoryBean = ContextHolder.getBean(SchedulerFactoryBean.class);
Scheduler scheduler = schedulerFactoryBean.getScheduler();
//获取触发器标识
TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobId(), SchedulerJob.JOB_GOURP);
//获取触发器trigger
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
if(null!=trigger){//如果已存在任务
delete(job);
}
if(SchedulerJob.STATUS_USED==job.getJobStatus()){
create(job);
}
}
}
/**
* 新建任务
* @Methods Name create
* @Create In 2014年9月23日 By lee
* @param scheduleJob
* @throws SchedulerException
*/
public static void create(SchedulerJob scheduleJob) throws SchedulerException {
SchedulerFactoryBean schedulerFactoryBean = ContextHolder.getBean(SchedulerFactoryBean.class);
Scheduler scheduler = schedulerFactoryBean.getScheduler();
//创建任务
JobDetail jobDetail = null;
if(AbstractQuartzManager.getState().equalsIgnoreCase(AbstractQuartzManager.STATE_SINGLE)){
jobDetail = JobBuilder.newJob(SingleQuartzJobFactory.class)
.withIdentity(scheduleJob.getJobId(), SchedulerJob.JOB_GOURP)
.build();
}else if(AbstractQuartzManager.getState().equalsIgnoreCase(AbstractQuartzManager.STATE_CLUSTER)){
jobDetail = JobBuilder.newJob(ClusterQuartzJobFactory.class)
.withIdentity(scheduleJob.getJobId(), SchedulerJob.JOB_GOURP)
.build();
}else{
return;
}
jobDetail.getJobDataMap().put("scheduleJob", scheduleJob);
//表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob
.getCronExpression());
//按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(scheduleJob.getJobId(), SchedulerJob.JOB_GOURP)
.withSchedule(scheduleBuilder)
.build();
scheduler.scheduleJob(jobDetail, trigger);
log.debug("=====定时任务["+scheduleJob.getJobId()+"/"+scheduleJob.getJobName()+"]载入成功=====");
}
/**
* 修改
* @Methods Name modify
* @Create In 2014年9月23日 By lee
* @param scheduleJob
* @throws SchedulerException
*/
public static void modify(SchedulerJob scheduleJob) throws SchedulerException {
SchedulerFactoryBean schedulerFactoryBean = ContextHolder.getBean(SchedulerFactoryBean.class);
Scheduler scheduler = schedulerFactoryBean.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobId(), SchedulerJob.JOB_GOURP);
//获取触发器trigger
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// Trigger已存在,那么更新相应的定时设置
//表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob
.getCronExpression());
//按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder()
.withIdentity(triggerKey)
.withSchedule(scheduleBuilder)
.build();
//按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
log.debug("=====定时任务["+scheduleJob.getJobId()+"/"+scheduleJob.getJobName()+"]更新成功=====");
}
/**
* 暂停任务
* @Methods Name pause
* @Create In 2014年9月23日 By lee
* @param scheduleJob
* @throws SchedulerException
*/
public static void pause(SchedulerJob scheduleJob) throws SchedulerException {
SchedulerFactoryBean schedulerFactoryBean = ContextHolder.getBean(SchedulerFactoryBean.class);
Scheduler scheduler = schedulerFactoryBean.getScheduler();
JobKey jobKey = JobKey.jobKey(scheduleJob.getJobId(), SchedulerJob.JOB_GOURP);
scheduler.pauseJob(jobKey);
log.debug("=====定时任务["+scheduleJob.getJobId()+"/"+scheduleJob.getJobName()+"]暂停成功=====");
}
/**
* 恢复任务
* @Methods Name resume
* @Create In 2014年9月23日 By lee
* @param scheduleJob
* @throws SchedulerException
*/
public static void resume(SchedulerJob scheduleJob) throws SchedulerException {
SchedulerFactoryBean schedulerFactoryBean = ContextHolder.getBean(SchedulerFactoryBean.class);
Scheduler scheduler = schedulerFactoryBean.getScheduler();
JobKey jobKey = JobKey.jobKey(scheduleJob.getJobId(), SchedulerJob.JOB_GOURP);
scheduler.resumeJob(jobKey);
log.debug("=====定时任务["+scheduleJob.getJobId()+"/"+scheduleJob.getJobName()+"]恢复成功=====");
}
/**
* 删除任务
* @Methods Name delete
* @Create In 2014年9月23日 By lee
* @param scheduleJob
* @throws SchedulerException
*/
public static void delete(SchedulerJob scheduleJob) throws SchedulerException {
SchedulerFactoryBean schedulerFactoryBean = ContextHolder.getBean(SchedulerFactoryBean.class);
Scheduler scheduler = schedulerFactoryBean.getScheduler();
JobKey jobKey = JobKey.jobKey(scheduleJob.getJobId(), SchedulerJob.JOB_GOURP);
scheduler.deleteJob(jobKey);
log.debug("=====定时任务["+scheduleJob.getJobId()+"/"+scheduleJob.getJobName()+"]注销成功=====");
}
/**
* 获取定时任务状态配置(single表示单机版,cluster表示集群版)
* @Methods Name getState
* @Create In 2015年1月14日 By lee
* @return
*/
public static String getState(){
if(StringUtils.isEmpty(schedulerState)){
schedulerState = PropertiesUtils.getProperty("app.scheduler.state");
}
return schedulerState;
}
}
针对单机增加一个SingleQuartzManager实现如下
/**
* Quartz单机管理器
* @ClassName: SingleQuartzManager
* @Create In 2014年12月31日 By lee
*/
public class SingleQuartzManager extends AbstractQuartzManager{
private static final Logger log = LoggerFactory.getLogger(SingleQuartzManager.class);
public static final int STATE_RUN = 1; //运行状态
public static final int STATE_WAIT = 0; //等待状态
/**
* 启动所有定时任务
* @throws SchedulerException
* @Methods Name startAll
* @Create In 2014年9月23日 By lee
*/
public static void startAll() throws SchedulerException{
if(AbstractQuartzManager.getState().equalsIgnoreCase(AbstractQuartzManager.STATE_SINGLE)){
SchedulerJobService schedulerJobService = ContextHolder.getBean(SchedulerJobService.class);
List<SchedulerJob> jobs = schedulerJobService.findAll();
for(SchedulerJob job : jobs){
if(SchedulerJob.STATUS_USED==job.getJobStatus()){
create(job);
}
}
log.debug("=====定时任务启动完成=====");
}
}
}
最最后补上配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> </bean> </beans>
这个实现只需要在spring中声明一下schedulerFactory,其他全部交给代码来完成。主要完成以下几个功能:
- 减少quartz配置;
- 通过配置文件动态修改quartz是否运行(我的配置文件也是动态的);
- 动态修改定时任务的状态预计运行规则。
PS:
- 代码中ContextHolder.getBean及获取spring bean实例方法类。
- SingleQuartzManager.startAll()项目启动的时候调一下就不提供代码了