當前位置:
首頁 >
前端技术
> javascript
>内容正文
javascript
Quartz在Spring中设置动态定时任务 .
生活随笔
收集整理的這篇文章主要介紹了
Quartz在Spring中设置动态定时任务 .
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
什么是動態定時任務:
是由客戶制定生成的,服務端只知道該去執行什么任務,但任務的定時是不確定的(是由客戶制定)。這樣總不能修改配置文件每定制個定時任務就增加一個trigger吧,即便允許客戶修改配置文件,但總需要重新啟動web服務啊,研究了下Quartz在Spring中的動態定時,發現: cronExpression是關鍵,如果可以動態設置cronExpression的值,也就說如果我們可以直接調用CronTriggerBean中設置cronExpression的方法,就可以順利解決問題了。
① targetMethod: 指定需要定時執行scheduleInfoManager中的simpleJobTest()方法
② concurrent:對于相同的JobDetail,當指定多個Trigger時, 很可能第一個job完成之前,第二個job就開始了。指定concurrent設為false,多個job不會并發運行,第二個job將不會在第一個job完成之前開始。
③ cronExpression:0/10 * * * * ?表示每10秒執行一次,具體可參考附表。
④ triggers:通過再添加其他的ref元素可在list中放置多個觸發器。scheduleInfoManager中的simpleJobTest()方法注意:此方法沒有參數,如果scheduleInfoManager有兩個方法simpleJobTest()和simpleJobTest(String argument),則spring只會去執行無參的simpleJobTest().
public void simpleJobTest()
{?????????
?? log.warn("uh oh, Job is scheduled !'" + "' Success...");????
}
?? Quartz在Spring中動態設置cronTrigger方法一Spring配置文件:
將定時器注入到業務邏輯層Manager
Xml代碼<bean?id="scheduleInfoManager"?class="com.lively.happyoa.jobs.webapp.manager.scheduleInfoManager">?? ?????????<property?name="scheduler"?ref="schedulerFactory"/>?? ?????</bean>?? ?????<bean?id="schedulerJobDetail"?class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">?? ?????????<property?name="targetObject"?ref="scheduleInfoManager"/>?? ?????????<property?name="targetMethod"?value="reScheduleJob"/>?? ?????????<property?name="concurrent"?value="false"/>?? ?????</bean>?? ?????<bean?id="cronTrigger"?class="org.springframework.scheduling.quartz.CronTriggerBean"?>?? ??????????<property?name="jobDetail"?ref="schedulerJobDetail"/>?? ??????????<property?name="cronExpression">?? ??????????????<value>0/10?*?*?*?*??</value>?? ??????????</property>?? ??????</bean>?? ?????<bean?id="schedulerFactory"?class="org.springframework.scheduling.quartz.SchedulerFactoryBean">?? ?????????<property?name="triggers">?? ?????????????<list>?? ?????????????????<ref?local="cronTrigger"/>?? ?????????????</list>?? ?????????</property>?? </bean>??
scheduleInfoManager中的reScheduleJob ()方法及相關方法① reScheduleJob讀取數據庫,獲得自定義定時器調度時間():
Java代碼private?Scheduler?scheduler;? ?? ?? //?設值注入,通過setter方法傳入被調用者的實例scheduler?? public?void?setScheduler(Scheduler?scheduler)?{??? ?? ?????this.scheduler?=?scheduler;??? ?? }??? ?? rivate?void?reScheduleJob()?throws?SchedulerException,ParseException?{ ?? ????????//?運行時可通過動態注入的scheduler得到trigger,注意采用這種注入方式在有的項目中會有問題,如果遇到注入問題,可以采取在運行方法時候,獲得bean來避免錯誤發生。?? ????????CronTriggerBean?trigger?=?(CronTriggerBean)?scheduler.getTrigger(????????????????"cronTrigger",?Scheduler.DEFAULT_GROUP); ?? ????????String?dbCronExpression?=?getCronExpressionFromDB(); ?? ????????String?originConExpression?=?trigger.getCronExpression(); ?? ????//?判斷從DB中取得的任務時間(dbCronExpression)和現在的quartz線程中的任務時間(originConExpression)是否相等?? ????//?如果相等,則表示用戶并沒有重新設定數據庫中的任務時間,這種情況不需要重新rescheduleJob?? ????????if(!originConExpression.equalsIgnoreCase(dbCronExpression)){ ?? ????????????trigger.setCronExpression(dbCronExpression); ?? ????????????scheduler.rescheduleJob("cronTrigger",?Scheduler.DEFAULT_GROUP,?trigger); ?? ????????} ?? ????//?下面是具體的job內容,可自行設置 ?? ????//?executeJobDetail();}??
② getCronExpressionFromDB():從數據庫中獲得dbCronExpression的具體代碼,由于使用了scheduleInfoManager,所以要在定義相應的setter方法:
Java代碼private?String?getCronExpressionFromDB(){ ?? ?????????String?sql="from?ScheduleInfo?scheduleInfo?where?1=1?"; ?? ?????????sql=sql+"?and?scheduleInfo.infoId?=?'"+"1"?+?"'"; ?? ?????????List?scheduleList?=?scheduleInfoManager.queryScheduleInListBySql(sql); ?? ?????????ScheduleInfo?scheduleInfo?=?(ScheduleInfo)scheduleList.get(0); ?? ?????????String?dbCronExpression?=?scheduleInfo.getCronExpression(); ?? ?????????return?dbCronExpression; ?? } ?
③ 在spring配置文件的scheduleInfoManager配置了相應的property(scheduler/ Java代碼scheduleInfoManager),要為其設置setter方法:? ?? private?Scheduler?scheduler; ?? ?????//?設值注入,通過setter方法傳入被調用者的實例scheduler?? ?????public?void?setScheduler(Scheduler?scheduler)?{ ?? ?????????this.scheduler?=?scheduler; ?? ????} ?? ?????private?ScheduleInfoManager?scheduleInfoManager; ?? ?????//?設值注入,通過setter方法傳入被調用者的實例scheduleInfoManager?? ?????public?void?setScheduleInfoManager(ScheduleInfoManager?scheduleInfoManager){ ?? ?????????this.scheduleInfoManager?=?scheduleInfoManager; ?? ?????} ?
Quartz在Spring中動態設置cronTrigger方法二在上面的2中我們可以看到,盡管已經可以動態進行rescheduleJob了,不過依然需要我們設置一個cronExpression,如果嘗試一下拿掉spring配置中的????????
<property name="cronExpression">
????????????? <value>0/10 * * * * ?</value>
</property>
則容器(如tomcat)啟動時會報錯。實際中我們希望tomcat啟動時就可以直接去讀數據庫,拿到相應的dbCronExpression,然后定時執行一個job,而不希望配置初始的cronExpression ,觀察下面的CronTriggerBean,考慮到cronExpression需要初始化,如果設定一個類InitializingCronTrigger繼承CronTriggerBean,然后在這個類中做一些讀取DB的初始化工作(設置cronExpression),問題就可以解決了。Spring配置文件:
Xml代碼<bean?id="scheduleInfoManager"?class="com.lively.happyoa.jobs.webapp.manager.ScheduleInfoManager">?????????<property?name="scheduler"?ref="schedulerFactory"/>?? ?????</bean>?? ?????<bean?id="schedulerJobDetail"?class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">?? ?????????<property?name="targetObject"?ref="scheduleInfoManager"/>?? ?????????<property?name="targetMethod"?value="reScheduleJob"/>?? ?????????<property?name="concurrent"?value="false"/>?? ?????</bean>?? ????<bean?id="cronTrigger"?class="com.lively.happyoa.jobs.webapp.manager.ScheduleInfoManager.InitializingCronTrigger">?? ??????????<property?name="jobDetail"?ref="schedulerJobDetail"/>?? ?????????<!--<property?name="cronExpression">?? ??????????????<value>0/10?*?*?*?*??</value>?? ??????????</property>-->?? ?????????<property?name="scheduleInfoManager"?ref="scheduleInfoManager"/>?? ??????</bean>?? ?????<bean?id="schedulerFactory"?class="org.springframework.scheduling.quartz.SchedulerFactoryBean">?? ?????????<property?name="triggers">?? ?????????????<list>?? ?????????????????<ref?local="cronTrigger"/>?? ?????????????</list>?? ?????????</property>?? </bean>??
InitializingCronTrigger中的相關方法注意:在注入scheduleInfoManager屬性的時候,我們可以去讀取DB任務時間(之所以放在setter方法中,是因為需要在設置scheduleInfoManager后進行getCronExpressionFromDB(),否則,也可以①②邏輯把放在類的構造函數中).注意InitializingCronTrigger必須extends CronTriggerBean.
Java代碼public?class?InitializingCronTrigger?extends?CronTriggerBean?implements?Serializable?{ ?? ?????private?ScheduleInfoManager?scheduleInfoManager; ?? ?????//?設值注入,通過setter方法傳入被調用者的實例scheduleInfoManager?? ?????public?void?setScheduleInfoManager(ScheduleInfoManager?scheduleInfoManager){ ?? ?????????this.scheduleInfoManager?=?scheduleInfoManager; ?? ?????????//?因為在getCronExpressionFromDB使用到了scheduleInfoManager,所以?? ?????????//?必須上一行代碼設置scheduleInfoManager后進行?? getCronExpressionFromDB ?? ?????????String?cronExpression?=?getCronExpressionFromDB?(); ?? ????//?① ?? ?????????//?因為extends?CronTriggerBean?,此處調用父類方法初始化cronExpression?? ????????setCronExpression(cronExpression); ?? ?????????????????????//?②} ?? ?????private?String?getCronExpressionFromDB(){ ?? ?????????String?sql="from?ScheduleInfo?scheduleInfo?where ?? ?1=1?"; ?? ?????????sql=sql+"?and?scheduleInfo.infoId?=?'"+"1"?+?"'"; ?? ?????????List?scheduleList?=?scheduleInfoManager.queryScheduleInListBySql(sql); ?? ?????????ScheduleInfo?scheduleInfo?=?(ScheduleInfo)scheduleList.get(0); ?? ?????????String?dbCronExpression?=?scheduleInfo.getCronExpression(); ?? ?????????return?dbCronExpression;}……} ? Quartz中時間參數說明 即Cron表達式
Cron表達式
Quartz使用類似于Linux下的Cron表達式定義時間規則,Cron表達式由6或7個由空格分隔的時間字段組成,如表1所示:
表1 Cron表達式時間字段
Cron表達式的時間字段除允許設置數值外,還可使用一些特殊的字符,提供列表、范圍、通配符等功能,細說如下:
●星號(*):可用在所有字段中,表示對應時間域的每一個時刻,例如,*在分鐘字段時,表示“每分鐘”;
●問號(?):該字符只在日期和星期字段中使用,它通常指定為“無意義的值”,相當于點位符;
●減號(-):表達一個范圍,如在小時字段中使用“10-12”,則表示從10到12點,即10,11,12;
●逗號(,):表達一個列表值,如在星期字段中使用“MON,WED,FRI”,則表示星期一,星期三和星期五;
●斜杠(/):x/y表達一個等步長序列,x為起始值,y為增量步長值。如在分鐘字段中使用0/15,則表示為0,15,30和45秒,而5/15在分鐘字段中表示5,20,35,50,你也可以使用*/y,它等同于0/y;
●L:該字符只在日期和星期字段中使用,代表“Last”的意思,但它在兩個字段中意思不同。L在日期字段中,表示這個月份的最后一天,如一月的31號,非閏年二月的28號;如果L用在星期中,則表示星期六,等同于7。但是,如果L出現在星期字段里,而且在前面有一個數值X,則表示“這個月的最后X天”,例如,6L表示該月的最后星期五;
●W:該字符只能出現在日期字段里,是對前導日期的修飾,表示離該日期最近的工作日。例如15W表示離該月15號最近的工作日,如果該月15號是星期六,則匹配14號星期五;如果15日是星期日,則匹配16號星期一;如果15號是星期二,那結果就是15號星期二。但必須注意關聯的匹配日期不能夠跨月,如你指定1W,如果1號是星期六,結果匹配的是3號星期一,而非上個月最后的那天。W字符串只能指定單一日期,而不能指定日期范圍;
●LW組合:在日期字段可以組合使用LW,它的意思是當月的最后一個工作日;
●井號(#):該字符只能在星期字段中使用,表示當月某個工作日。如6#3表示當月的第三個星期五(6表示星期五,#3表示當前的第三個),而4#5表示當月的第五個星期三,假設當月沒有第五個星期三,忽略不觸發;
● C:該字符只在日期和星期字段中使用,代表“Calendar”的意思。它的意思是計劃所關聯的日期,如果日期沒有被關聯,則相當于日歷中所有日期。例如5C在日期字段中就相當于日歷5日以后的第一天。1C在星期字段中相當于星期日后的第一天。
Cron表達式對特殊字符的大小寫不敏感,對代表星期的縮寫英文大小寫也不敏感。
表2下面給出一些完整的Cron表示式的實例:
表2 Cron表示式示例
表示式
說明
注意:CronTriggerBean的cronExpression屬性指定格式:至少6個時間元素,上面表示每天的15:37-38分執行1次任務。
時間元素(按照順序):
秒(0-59):
分(0-59):
小時(0-23):
每月第幾天(1-31):
月(1-12或JAN-DEC):
每星期第幾天(1-7或SUN-SAT):
年(1970-2099):
其中:不用設置的用”?”.
(1)每月第幾天和每星期第幾天是互斥的,兩個只能設置1個。如果有好幾個時間點,可以使用”,”符號,例如:”0 0 10,12,14 * * ?”表示每天的10時,12時,14時執行Job.
(2)對于連續時間可以使用”-”符號。例如:”0 10,12,14 1-15 * ?”表示每月的1到15日10時,12時,14時執行Job.
(3)時間格式的年可以不用制定。例如”0 0 10,12,14 ? MON 2006”表示2006年每星期一的10時,12時,14時執行Job.?
是由客戶制定生成的,服務端只知道該去執行什么任務,但任務的定時是不確定的(是由客戶制定)。這樣總不能修改配置文件每定制個定時任務就增加一個trigger吧,即便允許客戶修改配置文件,但總需要重新啟動web服務啊,研究了下Quartz在Spring中的動態定時,發現: cronExpression是關鍵,如果可以動態設置cronExpression的值,也就說如果我們可以直接調用CronTriggerBean中設置cronExpression的方法,就可以順利解決問題了。
① targetMethod: 指定需要定時執行scheduleInfoManager中的simpleJobTest()方法
② concurrent:對于相同的JobDetail,當指定多個Trigger時, 很可能第一個job完成之前,第二個job就開始了。指定concurrent設為false,多個job不會并發運行,第二個job將不會在第一個job完成之前開始。
③ cronExpression:0/10 * * * * ?表示每10秒執行一次,具體可參考附表。
④ triggers:通過再添加其他的ref元素可在list中放置多個觸發器。scheduleInfoManager中的simpleJobTest()方法注意:此方法沒有參數,如果scheduleInfoManager有兩個方法simpleJobTest()和simpleJobTest(String argument),則spring只會去執行無參的simpleJobTest().
public void simpleJobTest()
{?????????
?? log.warn("uh oh, Job is scheduled !'" + "' Success...");????
}
?? Quartz在Spring中動態設置cronTrigger方法一Spring配置文件:
將定時器注入到業務邏輯層Manager
Xml代碼
scheduleInfoManager中的reScheduleJob ()方法及相關方法① reScheduleJob讀取數據庫,獲得自定義定時器調度時間():
Java代碼
② getCronExpressionFromDB():從數據庫中獲得dbCronExpression的具體代碼,由于使用了scheduleInfoManager,所以要在定義相應的setter方法:
Java代碼
③ 在spring配置文件的scheduleInfoManager配置了相應的property(scheduler/ Java代碼
Quartz在Spring中動態設置cronTrigger方法二在上面的2中我們可以看到,盡管已經可以動態進行rescheduleJob了,不過依然需要我們設置一個cronExpression,如果嘗試一下拿掉spring配置中的????????
<property name="cronExpression">
????????????? <value>0/10 * * * * ?</value>
</property>
則容器(如tomcat)啟動時會報錯。實際中我們希望tomcat啟動時就可以直接去讀數據庫,拿到相應的dbCronExpression,然后定時執行一個job,而不希望配置初始的cronExpression ,觀察下面的CronTriggerBean,考慮到cronExpression需要初始化,如果設定一個類InitializingCronTrigger繼承CronTriggerBean,然后在這個類中做一些讀取DB的初始化工作(設置cronExpression),問題就可以解決了。Spring配置文件:
Xml代碼
InitializingCronTrigger中的相關方法注意:在注入scheduleInfoManager屬性的時候,我們可以去讀取DB任務時間(之所以放在setter方法中,是因為需要在設置scheduleInfoManager后進行getCronExpressionFromDB(),否則,也可以①②邏輯把放在類的構造函數中).注意InitializingCronTrigger必須extends CronTriggerBean.
Java代碼
Cron表達式
Quartz使用類似于Linux下的Cron表達式定義時間規則,Cron表達式由6或7個由空格分隔的時間字段組成,如表1所示:
表1 Cron表達式時間字段
| 位置 |
| ? |
| 時間域名 允許值 允許的特殊字符 |
| ? |
| ? |
| ? |
| 1 秒 0-59 , - * / |
| ? |
| 2 分鐘 0-59 , - * / |
| ? |
| 3 小時 0-23 , - * / |
| ? |
| 4 日期 1-31 , - * ? / L W C |
| ? |
| 5 月份 1-12 , - * / |
| ? |
| 6 星期 1-7 , - * ? / L C # |
| ? |
| 7 年(可選) 空值1970-2099 , - * / |
Cron表達式的時間字段除允許設置數值外,還可使用一些特殊的字符,提供列表、范圍、通配符等功能,細說如下:
●星號(*):可用在所有字段中,表示對應時間域的每一個時刻,例如,*在分鐘字段時,表示“每分鐘”;
●問號(?):該字符只在日期和星期字段中使用,它通常指定為“無意義的值”,相當于點位符;
●減號(-):表達一個范圍,如在小時字段中使用“10-12”,則表示從10到12點,即10,11,12;
●逗號(,):表達一個列表值,如在星期字段中使用“MON,WED,FRI”,則表示星期一,星期三和星期五;
●斜杠(/):x/y表達一個等步長序列,x為起始值,y為增量步長值。如在分鐘字段中使用0/15,則表示為0,15,30和45秒,而5/15在分鐘字段中表示5,20,35,50,你也可以使用*/y,它等同于0/y;
●L:該字符只在日期和星期字段中使用,代表“Last”的意思,但它在兩個字段中意思不同。L在日期字段中,表示這個月份的最后一天,如一月的31號,非閏年二月的28號;如果L用在星期中,則表示星期六,等同于7。但是,如果L出現在星期字段里,而且在前面有一個數值X,則表示“這個月的最后X天”,例如,6L表示該月的最后星期五;
●W:該字符只能出現在日期字段里,是對前導日期的修飾,表示離該日期最近的工作日。例如15W表示離該月15號最近的工作日,如果該月15號是星期六,則匹配14號星期五;如果15日是星期日,則匹配16號星期一;如果15號是星期二,那結果就是15號星期二。但必須注意關聯的匹配日期不能夠跨月,如你指定1W,如果1號是星期六,結果匹配的是3號星期一,而非上個月最后的那天。W字符串只能指定單一日期,而不能指定日期范圍;
●LW組合:在日期字段可以組合使用LW,它的意思是當月的最后一個工作日;
●井號(#):該字符只能在星期字段中使用,表示當月某個工作日。如6#3表示當月的第三個星期五(6表示星期五,#3表示當前的第三個),而4#5表示當月的第五個星期三,假設當月沒有第五個星期三,忽略不觸發;
● C:該字符只在日期和星期字段中使用,代表“Calendar”的意思。它的意思是計劃所關聯的日期,如果日期沒有被關聯,則相當于日歷中所有日期。例如5C在日期字段中就相當于日歷5日以后的第一天。1C在星期字段中相當于星期日后的第一天。
Cron表達式對特殊字符的大小寫不敏感,對代表星期的縮寫英文大小寫也不敏感。
表2下面給出一些完整的Cron表示式的實例:
表2 Cron表示式示例
表示式
說明
| ? |
| ? |
| "0 0 12 * * ? " 每天12點運行 |
| ? |
| "0 15 10 ? * *" 每天10:15運行 |
| ? |
| "0 15 10 * * ?" 每天10:15運行 |
| ? |
| "0 15 10 * * ? *" 每天10:15運行 |
| ? |
| "0 15 10 * * ? 2008" 在2008年的每天10:15運行 |
| ? |
| "0 * 14 * * ?" 每天14點到15點之間每分鐘運行一次,開始于14:00,結束于14:59。 |
| ? |
| "0 0/5 14 * * ?" 每天14點到15點每5分鐘運行一次,開始于14:00,結束于14:55。 |
| ? |
| "0 0/5 14,18 * * ?" 每天14點到15點每5分鐘運行一次,此外每天18點到19點每5鐘也運行一次。 |
| ? |
| "0 0-5 14 * * ?" 每天14:00點到14:05,每分鐘運行一次。 |
| ? |
| "0 10,44 14 ? 3 WED" 3月每周三的14:10分到14:44,每分鐘運行一次。 |
| ? |
| "0 15 10 ? * MON-FRI" 每周一,二,三,四,五的10:15分運行。 |
| ? |
| "0 15 10 15 * ?" 每月15日10:15分運行。 |
| ? |
| "0 15 10 L * ?" 每月最后一天10:15分運行。 |
| ? |
| "0 15 10 ? * 6L" 每月最后一個星期五10:15分運行。 |
| ? |
| "0 15 10 ? * 6L 2007-2009" 在2007,2008,2009年每個月的最后一個星期五的10:15分運行。 |
| ? |
| "0 15 10 ? * 6#3" 每月第三個星期五的10:15分運行。 |
| ? |
| ? |
注意:CronTriggerBean的cronExpression屬性指定格式:至少6個時間元素,上面表示每天的15:37-38分執行1次任務。
時間元素(按照順序):
秒(0-59):
分(0-59):
小時(0-23):
每月第幾天(1-31):
月(1-12或JAN-DEC):
每星期第幾天(1-7或SUN-SAT):
年(1970-2099):
其中:不用設置的用”?”.
(1)每月第幾天和每星期第幾天是互斥的,兩個只能設置1個。如果有好幾個時間點,可以使用”,”符號,例如:”0 0 10,12,14 * * ?”表示每天的10時,12時,14時執行Job.
(2)對于連續時間可以使用”-”符號。例如:”0 10,12,14 1-15 * ?”表示每月的1到15日10時,12時,14時執行Job.
(3)時間格式的年可以不用制定。例如”0 0 10,12,14 ? MON 2006”表示2006年每星期一的10時,12時,14時執行Job.?
總結
以上是生活随笔為你收集整理的Quartz在Spring中设置动态定时任务 .的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CXF2.7.3 与spring 3集成
- 下一篇: 在linux下修改oracle字符集