EJB 2.1 雖內建 TimerService,但部份應用伺服器不支援,或專案未使用 EJB 架構。為滿足定時觸發業務邏輯的需求,筆者設計了一個獨立、輕量的 TimerService 實作,無需依賴特定容器即可在 Web 應用中運行。
TimerTask,負責週期性掃描並觸發到期工作execute() 與 getNextExeDate()public class TimerService {
public static final long PERIOD = 1000 * 60 * 60; // 1 小時輪詢間隔
private Timer timer = new Timer(false);
private TimerSchedule schedule = null;
public void start() throws Exception {
schedule = new TimerSchedule();
schedule.addTimerJob(new SomeTimerJob()); // 註冊具體工作
timer.schedule(schedule, 0, PERIOD); // 立即啟動,每小時執行一次
}
public void stop() throws Exception {
timer.cancel();
}
}
public class TimerSchedule extends TimerTask {
private List<TimerJob> jobs = new ArrayList<>();
public void addTimerJob(TimerJob job) { jobs.add(job); }
@Override
public void run() {
Date now = Calendar.getInstance().getTime();
for (TimerJob job : jobs) {
Date next = job.getNextExeDate();
if (isTimeMatch(now, next)) {
job.execute(); // 觸發業務邏輯
}
}
}
private boolean isTimeMatch(Date now, Date next) {
long diff = next.getTime() - now.getTime();
return diff >= 0 && diff <= TimerService.PERIOD; // 在一個輪詢週期內視為到期
}
}
public class TimerJobExample implements TimerJob {
private Calendar nextDate;
public TimerJobExample() {
nextDate = Calendar.getInstance();
nextDate.add(Calendar.DAY_OF_MONTH, 1);
nextDate.set(Calendar.HOUR_OF_DAY, 1); // 設為隔天凌晨 1 點
}
@Override
public void execute() {
nextDate.add(Calendar.DAY_OF_MONTH, 1); // 更新下次執行時間
nextDate.set(Calendar.HOUR_OF_DAY, 1);
callBusinessLogic();
}
@Override
public Date getNextExeDate() { return nextDate.getTime(); }
private void callBusinessLogic() {
System.out.println("TimerJobExample call EJB function: " + new Date());
// 此處放入實際業務呼叫,如 EJB、Spring Bean、資料庫作業等
}
}
<%@ page import="com.example.timer.*" %>
<%
TimerService service = (TimerService) application.getAttribute("timerService");
boolean isStart = true;
if (service == null) {
service = new TimerService();
application.setAttribute("timerService", service);
service.start();
} else {
service.stop();
application.removeAttribute("timerService");
isStart = false;
}
%>
<html><body><h1><%= isStart ? "start ok" : "stop ok" %></h1></body></html>
將上述 JSP 部署於 Web 應用中,瀏覽即可切換排程服務狀態,適合測試與簡易管理介面。
TimerService 的專案TimerJob 實作