本文内容 通过xml配置一个调度器Scheduler,所有的任务通过该调度器来进行调度,结合官方提供的数据结构以及调度实现来达到前端控制定时器的目的。
调度器Scheduler的作用 调度器是Quartz的核心组成部分,其作用是调度Job能够被Trigger触发,是Quartz的驱动。 下图是列出来的定时器的核心概念、组成部分以及
调度器的创建 Scheduler的实现类有以下几个:
RemoteScheduler: 远程调度器;
StdScheduler:默认标准调度器(最为常用的);
RemoteMBeanScheduler:抽象类,
JBoss4RMIRemoteMBeanScheduler:是抽象类RemoteMBeanScheduler
的实现类 调度器的创建主要是通过其工厂模式创建的,创建方式有:
StdSchedulerFactory;
使用一组参数(java.util.Properties)来创建和初始化Quartz调度器;
配置参数一般在quartz.properties中
调用getScheduler方法就能创建和初始化调度器对象;
通过new StdSchedulerFactory().getScheduler();
来获取调度器。
DirectSchedulerFactory;
定时器创建以后,可以进行增加、删除以及显示Job和Trigger,对Job进行暂停/恢复等操作,调用了.start()方法后,Scheduler才正式开始执行Job和Trigger;
StdSchedulerFactory StdSchedulerFactory依赖于一系列属性决定如何产生Scheduler,提供配置信息的方式如下:
通过java.util.Properties属性实例;
通过外部属性文件提供;
通过含有属性文件内容的java.io.InputStream提供;
1 2 3 4 5 6 7 factory.initialize(); scheduler = factory.getScheduler("quartzScheduler" );
前端控制定时器暂停、恢复等核心方法 原理:配置定时器项目默认调度器名字,并结合quartz官方提供的表结构以及自动从数据库加载定时器配置的机制,使用调度器Scheduler的几个核心方法结合数据库配置达到使用前端界面控制定时器恢复、执行等操作。
void start(); // 启动
void standby();// 挂起
void shutdown();// 关闭
void shutdown(true); // 等待所有正在执行的job执行完毕之后,再关闭scheduler;
暂停定时器核心方法 修改数据库的执行器状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Override public Message updateJobStatus (QuartzJobInfo job) { QuartzTriggers triggers = new QuartzTriggers (); triggers.setSchedName(job.getSchedName()); triggers.setTriggerGroup(job.getTriggerGroup()); triggers.setTriggerName(job.getTriggerName()); triggers.setTriggerState(job.getTriggerState()); quartzTriggersDao.updateByPrimaryKeySelective(triggers); if (QRTZ_TRIGGER_STATUS_WAITING.equals(job.getTriggerState())) { quartzManager.resumeJob(job.getJobName(), job.getJobGroup()); } else { quartzManager.pauseJob(job.getJobName(), job.getJobGroup()); } return Message.success(); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public void pauseJob (String jobName, String jobGroupName) { JobKey jobKey = JobKey.jobKey(jobName, jobGroupName); try { scheduler.pauseJob(jobKey); } catch (SchedulerException e) { throw new BusinessException ("暂停任务[" + jobGroupName + SPLIT_DOT + jobName + "]中出现异常!" , e); } catch (IllegalArgumentException e) { throw new BusinessException ("暂停任务[" + jobGroupName + SPLIT_DOT + jobName + "]中出现异常!" , e); } }
恢复定时器核心方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public void resumeJob (String jobName, String jobGroupName) { JobKey jobKey = JobKey.jobKey(jobName, jobGroupName); try { scheduler.resumeJob(jobKey); } catch (SchedulerException e) { throw new BusinessException ("恢复任务[" + jobGroupName + SPLIT_DOT + jobName + "]中出现异常!" , e); } }
效果
回顾 定时器配置:SimpleTrigger和CronTrigger spring-servlet.xml 中添加配置,用于托付给spring来管理;
配置JobDetail;
配置Trigger;
配置Scheduler; 首先配置JobDetail,前面的概念中也了解到定义的方式,方式如下:
MethodInvokingJobDetailFactoryBean
JobDetailFactoryBean:可以传入参数jobDataMap;比较灵活;
extends QuartzJobBean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 <description > Quartz定时器配置</description > <bean id ="lxJobDetail" class ="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean" > <property name ="targetObject" ref ="lxJobDetailBean" /> <property name ="targetMethod" value ="init" /> </bean > <bean id ="lxJobDetailBean1" class ="org.springframework.scheduling.quartz.JobDetailFactoryBean" > <property name ="jobClass" value ="com.weyoung.platform.quartz.schedule.LxQuartzJobBean" /> <property name ="jobDataMap" > <map > <entry key ="anotherBean" value-ref ="anotherBean" /> </map > </property > <property name ="durability" value ="true" /> </bean > <bean id ="lxSimpleTrigger" class ="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean" > <property name ="jobDetail" ref ="lxJobDetail" /> <property name ="startDelay" value ="1000" /> <property name ="repeatInterval" value ="2000" /> </bean > <bean id ="lxCronTrigger" class ="org.springframework.scheduling.quartz.CronTriggerFactoryBean" > <property name ="jobDetail" ref ="lxJobDetailBean1" /> <property name ="cronExpression" value ="0/5 * * ? * *" /> </bean > <bean id ="lxQuartzScheduler" class ="org.springframework.scheduling.quartz.SchedulerFactoryBean" > <property name ="jobDetails" > <list > <ref bean ="lxJobDetail" /> <ref bean ="lxJobDetailBean1" /> </list > </property > <property name ="triggers" > <list > <ref bean ="lxSimpleTrigger" /> <ref bean ="lxCronTrigger" /> </list > </property > </bean >
其中,定义的类lxJobDetailBean、lxJobDetailBean1、anotherBean代码如下: LxJobDetailBean.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package com.weyoung.platform.quartz.schedule;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;import java.text.SimpleDateFormat;import java.util.Date;@Component("lxJobDetailBean") public class LxJobDetailBean { private static final Logger LOGGER = LoggerFactory.getLogger(LxJobDetailBean.class); public void init () { Date date = new Date (); SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd hh:mm:ss" ); LOGGER.info("-----------lxJobDetailBean.init-----------" + sdf.format(date)); } }
LxQuartzJobBean.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 package com.weyoung.platform.quartz.schedule;import com.weyoung.platform.quartz.entity.AnotherBean;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.scheduling.quartz.QuartzJobBean;import java.text.SimpleDateFormat;import java.util.Date;public class LxQuartzJobBean extends QuartzJobBean { private AnotherBean anotherBean; private static final Logger LOGGER = LoggerFactory.getLogger(LxQuartzJobBean.class); @Override protected void executeInternal (JobExecutionContext jobExecutionContext) throws JobExecutionException { Date date = new Date (); SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd hh:mm:ss" ); LOGGER.info("---------LxQuartzJobBean.executeInternal---------" + sdf.format(date)); } public void setAnotherBean (AnotherBean anotherBean) { this .anotherBean = anotherBean; } }
AnotherBean.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package com.weyoung.platform.quartz.entity;import org.springframework.stereotype.Component;@Component("anotherBean") public class AnotherBean { public void someMessage () { } }
Quartz中作业存储方式
RAMJobStore:作业、触发器、调度信息存储在内存中,这种方式存取速度比较快,但是如果定时器项目重启或者崩溃的话,存储的信息都会丢失;
JDBC作业存储:作业、触发器、调度信息存储在数据库中,支持事务,支持集群;
前面的笔记里面记录了Quartz官方提供的表结构及创建脚本等,使用该脚本创建数据库;
修改调度器信息及使用quartz.propertie文件配置 我的项目暂时是把定时器放在项目主程序中,也是使用同一个数据库,当然也可以分开。如果需要自己配置数据库的话,在quartz.properties中配置就行。 因此,修改spring-quartz.xml
配置如下:
1 2 3 4 5 6 7 8 9 10 <bean id ="lxQuartzScheduler" class ="org.springframework.scheduling.quartz.SchedulerFactoryBean" > <property name ="dataSource" ref ="masterDataSource" /> <property name ="overwriteExistingJobs" value ="true" /> <property name ="autoStartup" value ="true" /> <property name ="startupDelay" value ="20" /> <property name ="configLocation" value ="classpath:config/quartz.properties" /> </bean >
quartz.properties文件的配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 org.quartz.scheduler.instanceName =lxQuartzScheduler org.quartz.scheduler.instanceid =AUTO org.quartz.scheduler.rmi.export =false org.quartz.scheduler.rmi.proxy =false org.quartz.scheduler.wrapJobExecutionInUserTransaction =false org.quartz.threadPool.class =org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount =10 org.quartz.threadPool.threadPriority =5 =========================================================================== 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.tablePrefix = QRTZ_ org.quartz.plugin.triggHistory.class =org.quartz.plugins.history.LoggingTriggerHistoryPlugin org.quartz.plugin.triggHistory.triggerFiredMessage =Trigger {1}.{0} fired job {6}.{5} at: {4, date, HH:mm:ss MM/dd/yyyy} org.quartz.plugin.triggHistory.triggerCompleteMessage =Trigger {1}.{0} completed firing job {6}.{5} at {4, date, HH:mm:ss MM/dd/yyyy} with resulting trigger instruction code: {9}
qrtz_triggers表中的字段特别解析: MISFIRE_INSTR:Misfire处理规则: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule();scheduleBuilder.withMisfireHandlingInstructionFireNow(); scheduleBuilder.withMisfireHandlingInstructionIgnoreMisfires(); scheduleBuilder.withMisfireHandlingInstructionNextWithExistingCount(); scheduleBuilder.withMisfireHandlingInstructionNextWithRemainingCount(); scheduleBuilder.withMisfireHandlingInstructionNowWithExistingCount(); scheduleBuilder.withMisfireHandlingInstructionNowWithRemainingCount(); CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("" );cronScheduleBuilder.withMisfireHandlingInstructionIgnoreMisfires(); cronScheduleBuilder.withMisfireHandlingInstructionDoNothing(); cronScheduleBuilder.withMisfireHandlingInstructionFireAndProceed();
错误 1 2 org.springframework.web.context.ContextLoader - Context initialization failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'quartzJobServiceImpl': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'quartzManager': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'lxQuartzScheduler' defined in class path resource [spring/spring-quartz.xml]: Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: javax/transaction/UserTransaction
是因为缺少jar包,添加如下依赖,即可
1 2 3 4 5 <dependency > <groupId > javax.transaction</groupId > <artifactId > jta</artifactId > <version > 1.1</version > </dependency >