一 SchedulerFactoryBean
SchedulerFactoryBean
這個類的真正作用
提供了對org.quartz.Scheduler的
創(chuàng)建與配置瘾蛋,并且會管理它的生命周期
與Spring同步
。
org.quartz.Scheduler
: 調(diào)度器矫限。所有的調(diào)度都是由它控制
該類可以幫助我們設置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
創(chuàng)建的,默認情況下我們在job實現(xiàn)類中注入spring對象都是無效
的哺哼。因為對象并沒有被spring納入管理佩抹。
這時我可以通過AutowireCapableBeanFactory
來幫助我們實現(xiàn)
@Component
public class JobFactory extends AdaptableJobFactory {
/**
* AutowireCapableBeanFactory接口是BeanFactory的子類,可以連接和填充那些生命周期不被Spring管理的已存在的bean實例
*/
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
/**
* 創(chuàng)建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;
}
}
方式二
本質(zhì)都是借助AutowireCapableBeanFactory來實現(xiàn)
//配置JobFactory,為quartz作業(yè)添加自動連接支持
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會覆蓋現(xiàn)在的Job取董。默認為false棍苹,即已定義的Job不會覆蓋現(xiàn)有的Job。(用于集群)
setAutoStartup
:設置自行啟動
setDataSource
:設置數(shù)據(jù)源茵汰,使用與項目統(tǒng)一數(shù)據(jù)源
setStartupDelay
:項目啟動完成后枢里,等待x秒后開始執(zhí)行調(diào)度器初始化
二 動態(tài)定時任務
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的創(chuàng)建方式
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關(guān)聯(lián)的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
說明替換失敗
栏豺,原因就是舊觸發(fā)器沒有找到,所以新的觸發(fā)器也不會
設置進去
替換失敗的原因一般有兩種
:
- 一種情況是傳入的triggerKey沒有與之匹配的豆胸,
- 另外一種情況就是舊觸發(fā)器的觸發(fā)時間已經(jīng)全部完成奥洼,在觸發(fā)完成后調(diào)度引擎會自動清除無用的觸發(fā)器,這種情況也會匹配不到晚胡。
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);
// 停止觸發(fā)器
scheduler.pauseTrigger(triggerKey);
// 移除觸發(fā)器
scheduler.unscheduleJob(triggerKey);
// 刪除任務
scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));
GroupMatcher
分組匹配
GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
三 監(jiān)聽器
分類
- JobListener
- TriggerListener
- SchedulerListener
概念
- 全局監(jiān)聽器
- 非全局監(jiān)聽器(只能接收到在其上注冊的Job或Trigger的事件灵奖,不在其上注冊的Job或Trigger則不會進行監(jiān)聽)
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
將要被執(zhí)行
時調(diào)用這個方法估盘。 - jobExecutionVetoed方法:(這個方法
正常情況下不執(zhí)行
,但是如果當TriggerListener中的vetoJobExecution方法返回true時,那么執(zhí)行這個方法; 需要注意的是 如果方法(23執(zhí)行 那么(2),(4)這個倆個方法不會執(zhí)行,因為任務被終止了嘛.) - jobWasExecuted方法:Scheduler在JobDetail被
執(zhí)行之后
調(diào)用這個方法
全局監(jiān)聽
// 創(chuàng)建并注冊一個全局的Job Listener
scheduler.getListenerManager().addJobListener(new SimpleJobListener(), EverythingMatcher.allJobs());
局部監(jiān)聽
// 創(chuàng)建并注冊一個指定任務的Job Listener
scheduler.getListenerManager().addJobListener(new SimpleJobListener(), KeyMatcher.keyEquals(JobKey.jobKey("HelloWorld1_Job", "HelloWorld1_Group")));
將同一任務組的任務注冊到監(jiān)聽器中
scheduler.getListenerManager().addJobListener(new SimpleJobListener(), GroupMatcher.jobGroupEquals("HelloWorld2_Group"));
將兩個任務組的任務注冊到監(jiān)聽器中
scheduler.getListenerManager().addJobListener(new SimpleJobListener(), OrMatcher.or(GroupMatcher.jobGroupEquals("HelloWorld1_Group"), GroupMatcher.jobGroupEquals("HelloWorld2_Group")));
TriggerListener
任務調(diào)度過程中瓷患,與觸發(fā)器Trigger相關(guān)的事件包括:觸發(fā)器觸發(fā)、觸發(fā)器未正常觸發(fā)忿檩、觸發(fā)器完成等尉尾。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方法:用于獲取觸發(fā)器的名稱
- triggerFired方法:當與監(jiān)聽器相關(guān)聯(lián)的
Trigger被觸發(fā)
爆阶,Job上的execute()
方法將
被執(zhí)行時燥透,Scheduler就調(diào)用該方法苫纤。 - vetoJobExecution方法:在 Trigger
觸發(fā)后
畔规,Job將
要被執(zhí)行時由 Scheduler 調(diào)用這個方法荡短。TriggerListener 給了一個選擇
去否決 Job 的執(zhí)行
敛劝。假如這個方法返回true
继薛,這個 Job 將不會為此次 Trigger 觸發(fā)而得到執(zhí)行
乞娄。 - triggerMisfired方法:Scheduler 調(diào)用這個方法是在 Trigger
錯過觸發(fā)
時惧互。你應該關(guān)注此方法中持續(xù)時間長的邏輯:在出現(xiàn)許多錯過觸發(fā)的 Trigger 時鳍刷,長邏輯會導致骨牌效應鱼的。你應當保持這上方法盡量的小理盆。 - triggerComplete方法:Trigger
被觸發(fā)
并且完成了 Job 的執(zhí)行
時,Scheduler 調(diào)用這個方法凑阶。
簡單實現(xiàn)
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");
}
}
各種注冊
// 創(chuàng)建并注冊一個全局的Trigger Listener
scheduler.getListenerManager().addTriggerListener(new SimpleTriggerListener("SimpleTrigger"), EverythingMatcher.allTriggers());
// 創(chuàng)建并注冊一個局部的Trigger Listener
// scheduler.getListenerManager().addTriggerListener(new SimpleTriggerListener("SimpleTrigger"), KeyMatcher.keyEquals(TriggerKey.triggerKey("HelloWord1_Job", "HelloWorld1_Group")));
// 創(chuàng)建并注冊一個特定組的Trigger Listener
// scheduler.getListenerManager().addTriggerListener(new SimpleTriggerListener("SimpleTrigger"), GroupMatcher.groupEquals("HelloWorld1_Group"));
SchedulerListener
SchedulerListener會在Scheduler的生命周期中關(guān)鍵事件發(fā)生時被調(diào)用猿规。與Scheduler有關(guān)的事件包括:增加一個job/trigger,刪除一個job/trigger宙橱,scheduler發(fā)生嚴重錯誤姨俩,關(guān)閉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時調(diào)用
- jobUnscheduled方法:用于卸載JobDetail時調(diào)用
- triggerFinalized方法:當一個 Trigger 來到了再也不會觸發(fā)的狀態(tài)時調(diào)用這個方法。除非這個 Job 已設置成了持久性环葵,否則它就會從 Scheduler 中移除调窍。
- triggersPaused方法:Scheduler 調(diào)用這個方法是發(fā)生在一個 Trigger 或 Trigger 組被暫停時。假如是 Trigger 組的話张遭,triggerName 參數(shù)將為 null邓萨。
- triggersResumed方法:Scheduler 調(diào)用這個方法是發(fā)生成一個 Trigger 或 Trigger 組從暫停中恢復時。假如是 Trigger 組的話帝璧,假如是 Trigger 組的話先誉,triggerName 參數(shù)將為 null。參數(shù)將為 null的烁。
- jobsPaused方法:當一個或一組 JobDetail 暫停時調(diào)用這個方法褐耳。
- jobsResumed方法:當一個或一組 Job 從暫停上恢復時調(diào)用這個方法。假如是一個 Job 組渴庆,jobName 參數(shù)將為 null铃芦。
- schedulerError方法:在 Scheduler 的正常運行期間產(chǎn)生一個嚴重錯誤時調(diào)用這個方法。
- schedulerStarted方法:當Scheduler 開啟時襟雷,調(diào)用該方法
- schedulerInStandbyMode方法: 當Scheduler處于StandBy模式時刃滓,調(diào)用該方法
- schedulerShutdown方法:當Scheduler停止時,調(diào)用該方法
- schedulingDataCleared方法:當Scheduler中的數(shù)據(jù)被清除時耸弄,調(diào)用該方法咧虎。
注冊于注銷
// 創(chuàng)建SchedulerListener
scheduler.getListenerManager().addSchedulerListener(new SimpleSchedulerListener());
// 移除對應的SchedulerListener
// scheduler.getListenerManager().removeSchedulerListener(new SimpleSchedulerListener());