一 SchedulerFactoryBean
SchedulerFactoryBean
这个类的真正作用
提供了对org.quartz.Scheduler的
创建与配置,并且会管理它的生命周期
与Spring同步
。
org.quartz.Scheduler
: 调度器。所有的调度都是由它控制
该类可以帮助我们设置Scheduler的一些属性
@Bean
public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource, JobFactory jobFactory) throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
//可选,QuartzScheduler启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录
factory.setOverwriteExistingJobs(true);
factory.setAutoStartup(true); //设置自行启动
factory.setDataSource(dataSource);
factory.setJobFactory(jobFactory);
factory.setQuartzProperties(quartzProperties());
return factory;
}
注入Scheduler
@Bean(name = "scheduler")
public Scheduler scheduler() {
return schedulerFactoryBean().getScheduler();
}
任务工厂JobFactory
job实例都是由quartz
的JobFactory
创建的,默认情况下我们在job实现类中注入spring对象都是无效
的。因为对象并没有被spring纳入管理。
这时我可以通过AutowireCapableBeanFactory
来帮助我们实现
@Component
public class JobFactory extends AdaptableJobFactory {
/**
* AutowireCapableBeanFactory接口是BeanFactory的子类,可以连接和填充那些生命周期不被Spring管理的已存在的bean实例
*/
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
/**
* 创建Job实例
* @param bundle
* @return
* @throws Exception
*/
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
// 实例化对象
Object jobInstance = super.createJobInstance(bundle);
// 进行注入(Spring管理该Bean)
capableBeanFactory.autowireBean(jobInstance);
//返回对象
return jobInstance;
}
}
方式二
本质都是借助AutowireCapableBeanFactory来实现
//配置JobFactory,为quartz作业添加自动连接支持
public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements
ApplicationContextAware {
private transient AutowireCapableBeanFactory beanFactory;
@Override
public void setApplicationContext(final ApplicationContext context) {
beanFactory = context.getAutowireCapableBeanFactory();
}
@Override
protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
final Object job = super.createJobInstance(bundle);
beanFactory.autowireBean(job);
return job;
}
}
读取quartz.properties
//从quartz.properties文件中读取Quartz配置属性
@Bean
public Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
然后factory.setQuartzProperties(quartzProperties());
其他配置
//可选,QuartzScheduler启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录
factory.setOverwriteExistingJobs(true);
factory.setAutoStartup(true); //设置自行启动
factory.setDataSource(dataSource);
setOverwriteExistingJobs
:设置是否任意一个已定义的Job会覆盖现在的Job。默认为false,即已定义的Job不会覆盖现有的Job。(用于集群)
setAutoStartup
:设置自行启动
setDataSource
:设置数据源,使用与项目统一数据源
setStartupDelay
:项目启动完成后,等待x秒后开始执行调度器初始化
二 动态定时任务
TriggerState
如Trigger.TriggerState.NONE
- STATE_BLOCKED 4 阻塞
- STATE_COMPLETE 2 完成
- STATE_ERROR 3 错误
- STATE_NONE -1 不存在
- STATE_NORMAL 0 正常
- STATE_PAUSED 1 暂停
TriggerKey triggerKey = new TriggerKey(name, group);
scheduler.getTriggerState(triggerKey).name())
Scheduler
Scheduler的创建方式
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
DirectSchedulerFactory factory = DirectSchedulerFactory.getInstance();
Scheduler scheduler1=factory.getScheduler();
常用方法
- 添加一个定时任务:
Date scheduleJob(JobDetail jobDetail,Trigger trigger) - 修改一个定时任务,主要是更改trigger:
Date rescheduleJob(String triggerName, String groupName, Trigger newTrigger) - 删除一个定时任务,同时也会将于该jobDetail关联的trigger一并删除:
boolean deleteJob(String jobName,String jobGroup) - 取得所有的jobDetail组
String[] getJobGroupNames() - 取得某个group下的所有的jobDetail
String[] getJobNames(String groupName) - 取得指定的jobDetail
JobDetail getJobDetail(String jobName, String jobGroup) - 取得指定的jobDetail的所有的Trigger
Trigger[] getTriggersOfJob(String jobName, String groupName) - 取得指定的Trigger
Trigger getTrigger(String triggerName, String triggerGroup)
rescheduleJob
Trigger trigger = newTrigger()
.withIdentity("newTrigger", "group1")
.startNow()
.build();
// tell the scheduler to remove the old trigger with the given key, and put the new one in its place
sched.rescheduleJob(triggerKey("oldTrigger", "group1"), trigger);
注意:sched.rescheduleJob(triggerKey("oldTrigger", "group1"), trigger); 这个方法返回一个Date
.
如果返回 null
说明替换失败
,原因就是旧触发器没有找到,所以新的触发器也不会
设置进去
替换失败的原因一般有两种
:
- 一种情况是传入的triggerKey没有与之匹配的,
- 另外一种情况就是旧触发器的触发时间已经全部完成,在触发完成后调度引擎会自动清除无用的触发器,这种情况也会匹配不到。
pauseAll
暂停所有任务
scheduler.pauseAll();
pauseJob
暂停某个任务
JobKey jobKey = new JobKey(name, group);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if (jobDetail == null) {
return;
}
scheduler.pauseJob(jobKey);
resumeAll
恢复所有任务
scheduler.resumeAll();
resumeJob
恢复某个任务
JobKey jobKey = new JobKey(name, group);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if (jobDetail == null) {
return;
}
scheduler.resumeJob(jobKey);
deleteJob
删除某个任务
JobKey jobKey = new JobKey(name, group);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if (jobDetail == null) {
return;
}
scheduler.deleteJob(jobKey);
deleteJob
移除一个任务
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
// 停止触发器
scheduler.pauseTrigger(triggerKey);
// 移除触发器
scheduler.unscheduleJob(triggerKey);
// 删除任务
scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));
GroupMatcher
分组匹配
GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
三 监听器
分类
- JobListener
- TriggerListener
- SchedulerListener
概念
- 全局监听器
- 非全局监听器(只能接收到在其上注册的Job或Trigger的事件,不在其上注册的Job或Trigger则不会进行监听)
JobListener
public interface JobListener {
public String getName();
public void jobToBeExecuted(JobExecutionContext context);
public void jobExecutionVetoed(JobExecutionContext context);
public void jobWasExecuted(JobExecutionContext context,JobExecutionException jobException);
}
- getName方法:用于获取该
JobListener的名称
。 - jobToBeExecuted方法:Scheduler在JobDetail
将要被执行
时调用这个方法。 - jobExecutionVetoed方法:(这个方法
正常情况下不执行
,但是如果当TriggerListener中的vetoJobExecution方法返回true时,那么执行这个方法; 需要注意的是 如果方法(23执行 那么(2),(4)这个俩个方法不会执行,因为任务被终止了嘛.) - jobWasExecuted方法:Scheduler在JobDetail被
执行之后
调用这个方法
全局监听
// 创建并注册一个全局的Job Listener
scheduler.getListenerManager().addJobListener(new SimpleJobListener(), EverythingMatcher.allJobs());
局部监听
// 创建并注册一个指定任务的Job Listener
scheduler.getListenerManager().addJobListener(new SimpleJobListener(), KeyMatcher.keyEquals(JobKey.jobKey("HelloWorld1_Job", "HelloWorld1_Group")));
将同一任务组的任务注册到监听器中
scheduler.getListenerManager().addJobListener(new SimpleJobListener(), GroupMatcher.jobGroupEquals("HelloWorld2_Group"));
将两个任务组的任务注册到监听器中
scheduler.getListenerManager().addJobListener(new SimpleJobListener(), OrMatcher.or(GroupMatcher.jobGroupEquals("HelloWorld1_Group"), GroupMatcher.jobGroupEquals("HelloWorld2_Group")));
TriggerListener
任务调度过程中,与触发器Trigger相关的事件包括:触发器触发、触发器未正常触发、触发器完成等。TriggerListener的接口如下:
public interface TriggerListener {
public String getName();
public void triggerFired(Trigger trigger, JobExecutionContext context);
public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context);
public void triggerMisfired(Trigger trigger);
public void triggerComplete(Trigger trigger, JobExecutionContext context,
int triggerInstructionCode);
}
- getName方法:用于获取触发器的名称
- triggerFired方法:当与监听器相关联的
Trigger被触发
,Job上的execute()
方法将
被执行时,Scheduler就调用该方法。 - vetoJobExecution方法:在 Trigger
触发后
,Job将
要被执行时由 Scheduler 调用这个方法。TriggerListener 给了一个选择
去否决 Job 的执行
。假如这个方法返回true
,这个 Job 将不会为此次 Trigger 触发而得到执行
。 - triggerMisfired方法:Scheduler 调用这个方法是在 Trigger
错过触发
时。你应该关注此方法中持续时间长的逻辑:在出现许多错过触发的 Trigger 时,长逻辑会导致骨牌效应。你应当保持这上方法尽量的小。 - triggerComplete方法:Trigger
被触发
并且完成了 Job 的执行
时,Scheduler 调用这个方法。
简单实现
package org.ws.quartz.test3;
import org.quartz.JobExecutionContext;
import org.quartz.Trigger;
import org.quartz.Trigger.CompletedExecutionInstruction;
import org.quartz.TriggerListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SimpleTriggerListener implements TriggerListener{
private static Logger logger = LoggerFactory.getLogger(SimpleTriggerListener.class);
private String name;
public SimpleTriggerListener(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public void triggerFired(Trigger trigger, JobExecutionContext context) {
String triggerName = trigger.getKey().getName();
logger.info(triggerName + " was fired");
}
@Override
public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {
String triggerName = trigger.getKey().getName();
logger.info(triggerName + " was not vetoed");
return false;
}
@Override
public void triggerMisfired(Trigger trigger) {
String triggerName = trigger.getKey().getName();
logger.info(triggerName + " misfired");
}
@Override
public void triggerComplete(Trigger trigger, JobExecutionContext context,
CompletedExecutionInstruction triggerInstructionCode) {
String triggerName = trigger.getKey().getName();
logger.info(triggerName + " is complete");
}
}
各种注册
// 创建并注册一个全局的Trigger Listener
scheduler.getListenerManager().addTriggerListener(new SimpleTriggerListener("SimpleTrigger"), EverythingMatcher.allTriggers());
// 创建并注册一个局部的Trigger Listener
// scheduler.getListenerManager().addTriggerListener(new SimpleTriggerListener("SimpleTrigger"), KeyMatcher.keyEquals(TriggerKey.triggerKey("HelloWord1_Job", "HelloWorld1_Group")));
// 创建并注册一个特定组的Trigger Listener
// scheduler.getListenerManager().addTriggerListener(new SimpleTriggerListener("SimpleTrigger"), GroupMatcher.groupEquals("HelloWorld1_Group"));
SchedulerListener
SchedulerListener会在Scheduler的生命周期中关键事件发生时被调用。与Scheduler有关的事件包括:增加一个job/trigger,删除一个job/trigger,scheduler发生严重错误,关闭scheduler等。
public interface SchedulerListener {
public void jobScheduled(Trigger trigger);
public void jobUnscheduled(String triggerName, String triggerGroup);
public void triggerFinalized(Trigger trigger);
public void triggersPaused(String triggerName, String triggerGroup);
public void triggersResumed(String triggerName, String triggerGroup);
public void jobsPaused(String jobName, String jobGroup);
public void jobsResumed(String jobName, String jobGroup);
public void schedulerError(String msg, SchedulerException cause);
public void schedulerStarted();
public void schedulerInStandbyMode();
public void schedulerShutdown();
public void schedulingDataCleared();
}
- jobScheduled方法:用于部署JobDetail时调用
- jobUnscheduled方法:用于卸载JobDetail时调用
- triggerFinalized方法:当一个 Trigger 来到了再也不会触发的状态时调用这个方法。除非这个 Job 已设置成了持久性,否则它就会从 Scheduler 中移除。
- triggersPaused方法:Scheduler 调用这个方法是发生在一个 Trigger 或 Trigger 组被暂停时。假如是 Trigger 组的话,triggerName 参数将为 null。
- triggersResumed方法:Scheduler 调用这个方法是发生成一个 Trigger 或 Trigger 组从暂停中恢复时。假如是 Trigger 组的话,假如是 Trigger 组的话,triggerName 参数将为 null。参数将为 null。
- jobsPaused方法:当一个或一组 JobDetail 暂停时调用这个方法。
- jobsResumed方法:当一个或一组 Job 从暂停上恢复时调用这个方法。假如是一个 Job 组,jobName 参数将为 null。
- schedulerError方法:在 Scheduler 的正常运行期间产生一个严重错误时调用这个方法。
- schedulerStarted方法:当Scheduler 开启时,调用该方法
- schedulerInStandbyMode方法: 当Scheduler处于StandBy模式时,调用该方法
- schedulerShutdown方法:当Scheduler停止时,调用该方法
- schedulingDataCleared方法:当Scheduler中的数据被清除时,调用该方法。
注册于注销
// 创建SchedulerListener
scheduler.getListenerManager().addSchedulerListener(new SimpleSchedulerListener());
// 移除对应的SchedulerListener
// scheduler.getListenerManager().removeSchedulerListener(new SimpleSchedulerListener());