用java.util.timer在web工程中實(shí)現(xiàn)類似觸發(fā)器的機(jī)制
?
現(xiàn)在正在做的項(xiàng)目要實(shí)現(xiàn)一個(gè)定時(shí)出帳的觸發(fā)器, 開始打算用spring整合的quartz工具來(lái)實(shí)現(xiàn)(同時(shí)spring也提供了對(duì)java.util.timer的支持),
spring對(duì)quartz整合的方式,是在配置文件中通過bean的property項(xiàng)設(shè)置一個(gè)crontrigger表達(dá)式來(lái)實(shí)現(xiàn)精確的時(shí)點(diǎn)觸發(fā),但是由于spring只有在啟動(dòng)的時(shí)候?qū)ψ⑷胫颠M(jìn)行讀取,這樣的話就很難實(shí)現(xiàn)通過運(yùn)行時(shí)讀取配置參數(shù),達(dá)到不用重啟服務(wù)即可改變出帳時(shí)間的目的,所以只好自己尋找好一點(diǎn)的解決方案.
?
在網(wǎng)上找到了,看了很受啟發(fā),我略做了一些修改,實(shí)現(xiàn)了在每個(gè)月的某一天的某一個(gè)時(shí)間進(jìn)行任務(wù)操作的功能.
?
代碼及注釋如下:
?
先要實(shí)現(xiàn)一個(gè)系統(tǒng)的監(jiān)聽器:
/**
*?
title:?
*?
description:?
*?
copyright:?copyright?(c)chen?meng?2005
*?
company:?陳盟?
*?
*? @author ?陳盟
*? @version ?1.0
*? @since ?2005-1-13?/?17:26:41
*/
package ?com.wellsoon.cttbj.vab.background;
import ?java.util.date;
import ?javax.servlet.servletcontextevent;
import ?javax.servlet.servletcontextlistener;
public ? class ?settleaccountlistener? implements ?servletcontextlistener?{
private ?java.util.timer?timer? = ? null ;
/* ?
*?@see?javax.servlet.servletcontextlistener#contextinitialized(javax.servlet.servletcontextevent)
*/
public ? void ?contextinitialized(servletcontextevent?event)?{
date?taskrun? = ? null ;
// ?todo?auto-generated?method?stub
taskrun? = ? new ?date();
timer? = ? new ?java.util.timer( true );
event.getservletcontext().log(定時(shí)器已啟動(dòng));?
/ 在這里每隔一分鐘輪詢一次出帳任務(wù),如果任務(wù)間隔比較大的話建議把這個(gè)值設(shè)的大一點(diǎn),但此設(shè)置值將間接影響可設(shè)定的觸發(fā)精度.
timer.schedule( new ?settleaccounttask(),? 0 ,? 60 * 1000 );? /
event.getservletcontext().log(已經(jīng)添加任務(wù)調(diào)度表);
}
/* ?
*?@see?javax.servlet.servletcontextlistener#contextdestroyed(javax.servlet.servletcontextevent)
*/
public ? void ?contextdestroyed(servletcontextevent?event)?{
// ?todo?auto-generated?method?stub
timer.cancel();
event.getservletcontext().log(定時(shí)器銷毀);
}
}
接著來(lái)看settleaccounttask的實(shí)現(xiàn):
/**
*?
title:?
*?
description:?
*?
copyright:?copyright?(c)chen?meng?2005
*?
company:?陳盟?
*?
*? @author ?陳盟
*? @version ?1.0
*? @since ?2005-1-13?/?17:35:55
*/
package ?com.wellsoon.cttbj.vab.background;
import ?java.util.calendar;
import ?java.util.date;
import ?java.util.timertask;
public ? class ?settleaccounttask? extends ?timertask?{
private ? static ? boolean ?isrunning? = ? false ;
private ? static ? long ?dotaskmillis? = ? 0l ;
public ? void ?run()?{
system.out.println(dotaskmillis);?
// 下面兩個(gè)值代表每月的哪一天幾點(diǎn)進(jìn)行實(shí)際任務(wù)操作.可以通過數(shù)據(jù)庫(kù)查詢獲得
int ?c_schedule_date? = ? 10 ;
int ?c_schedule_hour? = ? 4 ;
calendar?cal? = ?calendar.getinstance();
// 如果任務(wù)量很大,在下次輪詢時(shí)仍在執(zhí)行上次輪詢的任務(wù),則跳過本次執(zhí)行,直接錯(cuò)過.
if ?( ! isrunning)?{
// 如果當(dāng)前系統(tǒng)時(shí)間的day_of_month和hour_of_day不滿足以下條件,則跳過實(shí)際操作.
if ?(c_schedule_date? == ?cal.get(calendar.day_of_month)?&&?c_schedule_hour? == ?cal.get(calendar.hour_of_day))?{
// 如果上次執(zhí)行任務(wù)的時(shí)間距此次輪詢時(shí)間間隔太短,則跳過實(shí)際操作.
if ((dotaskmillis? 2 * 60 * 60 * 1000 )? < ?cal.gettimeinmillis())?{
// ?詳細(xì)任務(wù)
isrunning? = ? true ;
system.out.println(執(zhí)行出帳操作);
dotaskmillis? = ?cal.gettimeinmillis();
system.out.println(dotaskmillis);
isrunning? = ? false ;
}
}
}? else ?{
system.out.println(錯(cuò)過);
}
}
}
最后,在web.xml中加上
<listener>
? <listener-class>
??? com.xxx.background.settleaccountlistener
? </listener-class>
</listener>
?
就可以了.
如果有更好的解決方式, 希望您回復(fù).