Spring中可以通過(guò)配置方便的實(shí)現(xiàn)周期性定時(shí)任務(wù)管理,這需要用到以下幾個(gè)類(lèi):
org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean--配置需要調(diào)度的Bean的某個(gè)方法
org.springframework.scheduling.quartz.SimpleTriggerBean--定時(shí)器,負(fù)責(zé)配置啟動(dòng)時(shí)間、執(zhí)行周期
org.springframework.scheduling.quartz.SchedulerFactoryBean--觸發(fā)器,負(fù)責(zé)配置所有定時(shí)器
實(shí)例如下:
注意以上4個(gè)Bean需要按順序配置,從配置屬性的字面意思,應(yīng)該很容易理解具體的參數(shù)含義。 另外對(duì)SchedulerFactoryBean的使用需要注意以下幾個(gè)方面:
1、SchedulerFactoryBean會(huì)自動(dòng)啟動(dòng)。
當(dāng)在spring文件中定義了多個(gè)SchedulerFactoryBean實(shí)例時(shí),一定要小心,因?yàn)檫@些ScheduleFactoryBean自從load進(jìn)程序里,就會(huì)自動(dòng)啟動(dòng)。如果要手動(dòng)控制,注意要將autoStartup屬性設(shè)置為false,注意如果沒(méi)有singleton="true",SchedulerFactoryBean就不是單獨(dú)存在的,autoStartup也就不能很好的手動(dòng)控制
定時(shí)器。
2、SchedulerFactoryBean暴露的是Scheduler,而不是SchedulerFactoryBean。
SchedulerFactoryBean實(shí)現(xiàn)了FactoryBean接口,必須實(shí)現(xiàn)兩個(gè)方法,一個(gè)是getObjectType,另外一個(gè)則是getObject;其中getObjectType定義了返回的類(lèi)型應(yīng)該為Scheduler,而getObject指定了返回的是其一個(gè)重要屬性scheduler,這個(gè)scheduler就是我們要獲得的調(diào)度。
若在配置文件里為SchedulerFactoryBean定義了id屬性為"scheduler",則在程序里調(diào)用getBean時(shí),需要注意getBean("scheduler")返回的是Scheduler對(duì)象
3、
SchedulerFactoryBean中有兩個(gè)很重要的屬性,一個(gè)是scheduler,另外一個(gè)是schedulerFactoryClass,spring通過(guò)用schedulerFactoryClass做代理來(lái)產(chǎn)生調(diào)度,并把它賦給scheduler。
private Class schedulerFactoryClass = StdSchedulerFactory.class;
//如果你沒(méi)有指定schedulerFactoryClass ,那么它用的是quartz中自帶的調(diào)度工廠,
this.scheduler = createScheduler(schedulerFactory, this.schedulerName);
//這里的schedulerName默認(rèn)傳進(jìn)來(lái)是空的,其實(shí)如果你不是用自己定義的schedulerFactoryClass
//恐怕也沒(méi)有什么意義,因?yàn)閏reateScheduler是這樣調(diào)用的
return schedulerFactory.getScheduler();
//顯然schedulerName并沒(méi)有用到,除非是你自行寫(xiě)一個(gè)schedulerFactory,并做好相應(yīng)處理,
//否則返回的這個(gè)scheduler一定是一個(gè)指定名稱(chēng)的調(diào)度
Scheduler sched = schedRep.lookup(getSchedulerName());
//這個(gè)sched就是要代理生成的scheduler,getSchedulerName只有一句話(huà),如下:
cfg.getStringProperty(PROP_SCHED_INSTANCE_NAME,"QuartzScheduler");
//如果我們沒(méi)有使用一些特殊的機(jī)制,那么返回的只能是一個(gè)固定的字符串。
如上說(shuō)述,如果我們希望不進(jìn)行改造,就在spring的配置文件中定義多個(gè)調(diào)度的方法來(lái)實(shí)現(xiàn)我們個(gè)性化的任務(wù)安排時(shí),可能并不可行。因?yàn)?/span>spring配置的scheduler只能有一個(gè),即使你定義了多個(gè)調(diào)度,那么其實(shí)實(shí)現(xiàn)的只有一個(gè),只是所有你希望指向不同調(diào)度的id都會(huì)指向它罷了,而這個(gè)調(diào)度會(huì)包含了其它所有調(diào)度中的任務(wù)。
4、抱錯(cuò):org.quartz.SchedulerException:
Repeat Interval cannot be zero
場(chǎng)景:該錯(cuò)誤通常是在引用了SimpleTriggerBean的時(shí)候沒(méi)有為repeatCount和repeatInterval賦值發(fā)生的,很奇怪,SimpleTriggerBean有一個(gè)空構(gòu)造函數(shù),在里面直接為repeatCount賦了一個(gè)REPEAT_INDEFINITELY,這樣,當(dāng)其進(jìn)入validate函數(shù)時(shí),會(huì)抱錯(cuò)。而quartz中的SimpleTrigger這兩個(gè)屬性默認(rèn)值均為0,不懂spring中為何這樣處理。
5、quartz和crontab的區(qū)別
a、quartz屬于用戶(hù)級(jí)別,crontab則屬于系統(tǒng)級(jí)別;
b、quartz調(diào)度的線(xiàn)程,所有線(xiàn)程共享一個(gè)jvm;crontab調(diào)度的則是應(yīng)用,每個(gè)應(yīng)用都獨(dú)立的占用資源。
6、quartz中加入并發(fā)多線(xiàn)程分析
a、quartz本身是有線(xiàn)程池支持的,這個(gè)可以用org.quartz.threadPool.threadCount屬性來(lái)設(shè)置線(xiàn)程池大小,quartz的任務(wù)可以由quartz的線(xiàn)程池自動(dòng)調(diào)度
b、對(duì)每個(gè)任務(wù)也可能起多線(xiàn)程,但是需要對(duì)并發(fā)數(shù)量做控制,可以考慮使用commons-pools提供的對(duì)象池機(jī)制
|
|
來(lái)自: 純屬愛(ài) > 《定時(shí)器》