quartz源码分析之深刻理解job,sheduler,calendar,trigger及listener之间的关系
org.quartz包
包org.quartz是Quartz的主包,包含了客戶端接口。
其中接口有:
Calendar接口:
定義了一個(gè)關(guān)聯(lián)Trigger可能(或者不可能)觸發(fā)的時(shí)間空間。它沒有定義觸發(fā)的真實(shí)時(shí)間,而是用在在普通的Schedule需要限制Trigger觸發(fā)的時(shí)候。大部分Calendar包含默認(rèn)所有的時(shí)間,并且用戶去排除部分時(shí)間。
因而,可以把Calendar看做是排除了block時(shí)間的時(shí)間(例如:一個(gè)每5分鐘觸發(fā)一次的調(diào)度在周末(sunday)不執(zhí)行,使用SimpleTrigger和WeeklyCalendar去排除周末這一天)。
注意:Calendar實(shí)現(xiàn)了序列化和可克隆接口。
?
?
Trigger接口:
?
?
?
?
?
?
CalendarIntervalTrigger:是一個(gè)具體的Trigger,用來觸發(fā)基于定時(shí)重復(fù)的JobDetail。
Trigger將會(huì)每隔N個(gè)calendar在trigger中定義的時(shí)間單元觸發(fā)一次。這個(gè)trigger不適合使用SimpleTrigger完成(例如由于每一個(gè)月的時(shí)間不是固定的描述),也不適用于CronTrigger(例如每5個(gè)月)。
若你使用Month作為時(shí)間間隔單位,請(qǐng)務(wù)必在設(shè)置開始時(shí)間時(shí)注意那天是否接近月底。例,如:你選擇1月31作為啟動(dòng)時(shí)間,trigger 將設(shè)置觸發(fā)間隔為月份,下次觸發(fā)時(shí)間為2.28,下下次為3月28,接下來的觸發(fā)時(shí)間定位每月的28號(hào),而不管那個(gè)月是否有31天。如果你需要一個(gè)在每月最后一天觸發(fā)的trigger(不管每月有多少天),請(qǐng)使用CronTrigger.
?
CronTrigger:使用CronExpression表達(dá)式作為觸發(fā)條件的Trigger的公開接口。
DailyTimeIntervalTrigger:用來觸發(fā)一個(gè)基于每天定時(shí)間隔執(zhí)行的JobDetail。Trigger在跟定的時(shí)間內(nèi)每隔N(個(gè)體RepeatInterval())秒、分、小時(shí)(getRepeatIntervalUnit())觸發(fā)一次。
例一:每天8:00~11:00之間每72分鐘執(zhí)行一次,它的觸發(fā)事件為8:00,9:12,10:24,然后明天繼續(xù):8:00,9:12,10:24。
例二:從周一到周五的每天9:20~16:47 每隔23分鐘執(zhí)行一次。
每天,開始時(shí)間被重置為startTimeOfDay,直至一天endTimeOfDay到之前,都將重復(fù)的間隔時(shí)間向上加。
TriggerListener接口
?
?
Job接口:
Job:job代表了要允許的任務(wù)即業(yè)務(wù)邏輯。它必須具有一個(gè)公開的無參構(gòu)造方法。JobDataMap提供了Job實(shí)例參數(shù)數(shù)據(jù)的機(jī)制,它會(huì)在一些實(shí)現(xiàn)給接口的類中需要這一機(jī)制。有唯一的方法:execute(JobExecutionContext context):當(dāng)一個(gè)關(guān)聯(lián)到這個(gè)job的Trigger需要觸發(fā)時(shí)由Scheduler來調(diào)用該方法。
?
JobDetail:保存一個(gè)job實(shí)例的詳細(xì)屬性。它在JobBuilder中創(chuàng)建/定義。
JobDetailImpl:存一個(gè)job實(shí)例的詳細(xì)屬性,Quartz不保存一個(gè)Job類的真實(shí)實(shí)例,相反,允許你通過使用JobDetail定義一個(gè)job實(shí)例。Job 有名稱和所屬的組別,scheduler可以通過組別和名稱來找到唯一的一個(gè)job。Trigger 是job被調(diào)度的機(jī)制,許多Trigger可以指向同一個(gè)Job,但一個(gè)Trigger僅僅能執(zhí)行一個(gè)Job。
??? private String name;
?
??? private String group = Scheduler.DEFAULT_GROUP;
?
??? private String description;
?
??? private Class<? extends Job> jobClass;
?
??? private JobDataMap jobDataMap;
?
??? private boolean durability = false;
?
??? private boolean shouldRecover = false;
?
??? private transient JobKey key = null;
其中,JobKey定義了job的名稱和組別。
JobBuilder:用來初始化JobDetail實(shí)例。
?
?
?
?
?
JobListener
實(shí)現(xiàn)了該接口的類會(huì)監(jiān)聽JobDetail執(zhí)行的方法。通常,使用Scheduler的應(yīng)用將不會(huì)應(yīng)用這一機(jī)制。
ListenerManager:JobListener提供了對(duì)Job執(zhí)行的監(jiān)聽;TriggerListener提供對(duì)trigger觸發(fā)的監(jiān)聽;SchedulerListener提供了Scheduler事件和錯(cuò)誤的監(jiān)聽。通過ListenerManager接口將Listener和本地scheduler關(guān)聯(lián)到一起。ListenerManagerImpl是實(shí)現(xiàn)類。
?
Listener的注冊(cè)順序是保持的,因此Listener的監(jiān)聽順序和他們注冊(cè)的順序一致。
?
JobFactory接口:
public class PropertySettingJobFactory extends SimpleJobFactory {}
public class SimpleJobFactory implements JobFactory {}
?
TriggerFiredBundle:JobStore返回給QuartzSchedulerThread的執(zhí)行時(shí)期數(shù)據(jù)。
?? private JobDetail job;
?
??? private OperableTrigger trigger;
?
??? private Calendar cal;
?
??? private boolean jobIsRecovering;
?
??? private Date fireTime;
?
??? private Date scheduledFireTime;
?
??? private Date prevFireTime;
?
??? private Date nextFireTime;
Scheduler接口:
一個(gè)scheduler維護(hù)一個(gè)JobDetail和一個(gè)或者多個(gè)Trigger的注冊(cè)。一旦注冊(cè),scheduler負(fù)責(zé)在job關(guān)聯(lián)的Trigger觸發(fā)時(shí)(當(dāng)調(diào)度到達(dá)時(shí)間)執(zhí)行該job。
Scheduler實(shí)例有SchedulerFactory創(chuàng)建產(chǎn)生。一個(gè)已經(jīng)創(chuàng)建或者初始化的scheduler可以被創(chuàng)建它的工廠查詢和使用。在一個(gè)scheduler被創(chuàng)建后,它處于”STAND-BY”模式,在觸發(fā)任何job前需要使用它的start()方法來啟動(dòng)。
客戶端程序通過定義一個(gè)實(shí)現(xiàn)了job接口的類來創(chuàng)建Job,JobDetail對(duì)象同時(shí)對(duì)創(chuàng)建(客戶端)來定義一個(gè)單獨(dú)的job實(shí)例。JobDetail實(shí)例然后通過ScheduleJob(JobDetail,Trigger)或者addJob(JobDetail,boolean)方法注冊(cè)到Scheduler。
Trigger定義用來觸發(fā)基于給定Scheduler的單獨(dú)的job實(shí)例,SimpleTrigger對(duì)觸發(fā)一次或精確時(shí)間的觸發(fā)、在給定延遲后重復(fù)觸發(fā)的應(yīng)用中非常有用。Contrigger允許基于一天中的具體時(shí)間、一周中的一天、一月中的一天、一年中的一個(gè)月的調(diào)度。
Job和trigger都具有名稱和關(guān)聯(lián)的組別,這是它們?cè)谝粋€(gè)單獨(dú)Scheduler的唯一身份識(shí)別碼。組別的這個(gè)特征在創(chuàng)建邏輯組或?qū)ob和Trigger進(jìn)行歸類時(shí)非常有用。如果你不想對(duì)給定的job和trigger指定一個(gè)分組,可以使用默認(rèn)組常量,這個(gè)常量已經(jīng)在接口中定義好了。
?
存儲(chǔ)的Job也可以手動(dòng)觸發(fā),通過使用trigger(String JobName,String jobGroup)這個(gè)方法可以實(shí)現(xiàn)手動(dòng)觸發(fā)job。
?
客戶端程序可能會(huì)對(duì)Quartz中的Listener接口感興趣,JobListener提供了對(duì)job執(zhí)行的監(jiān)聽;TriggerListner提供了對(duì)Trigger觸發(fā)的監(jiān)聽;SchedulerListener提供了對(duì)事件調(diào)度和錯(cuò)誤的監(jiān)聽。通過使用ListenerManager接口將Listener和本地的Scheduler關(guān)聯(lián)起來。Scheduler的創(chuàng)建和配置都可以自定義。請(qǐng)參考發(fā)布的Quartz的文檔。
?
?
SchedulerListener接口:
<略>
?
org.quartz.core包
JobRunShell
jobRunShell實(shí)例負(fù)責(zé)為job運(yùn)行提供安全的環(huán)境、運(yùn)行job所需工作、捕獲排除的任何異常、更新執(zhí)行完成job代碼的Trigger等。
jobRunShell實(shí)例由JobRunShellFactory創(chuàng)建,當(dāng)sheduler決定觸發(fā)一個(gè)job時(shí),QuartzSchedulerThread從配置的線程池中返回一個(gè)shell??匆幌耲obRunShel的調(diào)用關(guān)系:
/**
???? * <p>
???? * Create a <code>QuartzScheduler</code> with the given configuration
???? * properties.
???? * </p>
???? *
???? * @see QuartzSchedulerResources
???? */
??? public QuartzScheduler(QuartzSchedulerResources resources, long idleWaitTime, @Deprecated long dbRetryInterval)
??????? throws SchedulerException {
??????? this.resources = resources;
??????? if (resources.getJobStore() instanceof JobListener) {
??????????? addInternalJobListener((JobListener)resources.getJobStore());
??????? }
?
??????? this.schedThread = new QuartzSchedulerThread(this, resources);
??????? ThreadExecutor schedThreadExecutor = resources.getThreadExecutor();
??????? schedThreadExecutor.execute(this.schedThread);
??????? if (idleWaitTime > 0) {
??????????? this.schedThread.setIdleWaitTime(idleWaitTime);
??????? }
?
??????? jobMgr = new ExecutingJobsManager();
??????? addInternalJobListener(jobMgr);
??????? errLogger = new ErrorLogger();
??????? addInternalSchedulerListener(errLogger);
?
??????? signaler = new SchedulerSignalerImpl(this, this.schedThread);
???????
??????? if(shouldRunUpdateCheck())
??????????? updateTimer = scheduleUpdateCheck();
??????? else
??????????? updateTimer = null;
???????
??????? getLog().info("Quartz Scheduler v." + getVersion() + " created.");
??? }
?
?
QuartzSchedulerThread啟動(dòng)時(shí)調(diào)用JobRunShell
JobRunShell shell = null;
try{
?? shell = qsRsrcs.getJobRunShellFactory().createJobRunShell(bndle);
?? shell.initialize(qs);
?? }
?
?
?
?
?
QuartzScheduler
這個(gè)類是Quartz的核心,間接繼承了Scheduler接口,包含了調(diào)度Job、注冊(cè)JobListener實(shí)例的方法。
QuartzSchedulerResources:包含了JobStore、線程池等創(chuàng)建一個(gè)QuartzScheduler實(shí)例所必須要的所有資源。
?
?
SchedulerContext:保存job運(yùn)行時(shí)需要的上下文/環(huán)境數(shù)據(jù),這個(gè)特征和J2EE中servlet的ServletContext特征特別相像。
以后的Quartz版本將會(huì)在代理實(shí)例和單獨(dú)的scheduler實(shí)例如何在SchedulerContext擴(kuò)展數(shù)據(jù)做出區(qū)分。
?
SchedulerSignaler:JobStore實(shí)例使用的接口,用來傳回信號(hào)到QuartzScheduler。
??? void notifyTriggerListenersMisfired(Trigger trigger);
?
??? void notifySchedulerListenersFinalized(Trigger trigger);
?
??? void notifySchedulerListenersJobDeleted(JobKey jobKey);
?
??? void signalSchedulingChange(long candidateNewNextFireTime);
?
void notifySchedulerListenersError(String string, SchedulerException jpe);
?
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/davidwang456/p/4237895.html
總結(jié)
以上是生活随笔為你收集整理的quartz源码分析之深刻理解job,sheduler,calendar,trigger及listener之间的关系的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: kafka入门:简介、使用场景、设计原理
- 下一篇: Linux ps aux指令詳解--转