| 方法 | 觸發時機 | 典型用途 |
| contextInitialized(ServletContextEvent) | Servlet 容器啟動、Web 應用部署完成 | 初始化資源、啟動排程任務、載入設定檔、建立連線池 |
| contextDestroyed(ServletContextEvent) | Servlet 容器關閉、Web 應用卸載 | 釋放資源、停止排程任務、關閉連線池、記錄關閉日誌 |
二、完整實作範例:簡訊回覆監聽器
2.1 監聽器主類別:ReplyListener.java
package com.hanweb.jcms;
import javax.servlet.*;
public class ReplyListener implements ServletContextListener {
private ReplyTimer rt = null;
public void contextInitialized(ServletContextEvent event) {
String status = "[SYS] SMS reply listener start.";
event.getServletContext().log(status); // 寫入 Servlet 容器日誌
System.out.println(status); // 主控台輸出
rt = new ReplyTimer(1); // 每 1 分鐘執行一次
rt.start();
}
public void contextDestroyed(ServletContextEvent event) {
String status = "[SYS] SMS reply listener stop.";
event.getServletContext().log(status);
System.out.println(status);
if (rt != null) {
rt.stop(); // 優雅停止 Timer
}
}
}
2.2 排程控制器:ReplyTimer.java
package com.hanweb.jcms;
import java.util.*;
public class ReplyTimer {
private final Timer timer = new Timer();
private final int intervalMinutes;
public ReplyTimer(int minutes) {
this.intervalMinutes = minutes;
}
public void start() {
Date firstRun = new Date(); // 立即首次執行
timer.schedule(new ReplyTask(), firstRun, intervalMinutes * 60 * 1000L);
}
public void stop() {
timer.cancel(); // 取消所有已排程任務,清理資源
}
}
2.3 具體任務邏輯:ReplyTask.java
package com.hanweb.jcms;
import java.util.*;
public class ReplyTask extends TimerTask {
public void doSomething() {
System.out.println("[SYS] SMS reply listener running...");
// 實際業務邏輯:查詢資料庫、呼叫簡訊閘道、更新狀態等
}
@Override
public void run() {
try {
doSomething();
} catch (Exception e) {
// 任務異常不應中斷 Timer,記錄錯誤並繼續下一輪
System.err.println("[ERR] SMS reply task failed: " + e.getMessage());
e.printStackTrace();
}
}
}
三、部署配置:web.xml 註冊監聽器
編譯後將 .class 檔案放入 WEB-INF/classes/ 目錄,並在 web.xml 中註冊:
<listener>
<listener-class>com.hanweb.jcms.ReplyListener</listener-class>
</listener>
容器啟動時會自動實例化 ReplyListener 並呼叫 contextInitialized(),無需額外配置。
四、進階實務考量
| 議題 | 建議做法 |
| 任務執行時間超過間隔 | 使用 timer.scheduleAtFixedRate() 固定頻率,或改用 ScheduledExecutorService (Java 5+) 更精確控制 |
| 叢集環境重複執行 | 引入分散式鎖(資料庫鎖、ZooKeeper、Redis Redlock)確保單節點執行 |
| 任務異常導致 Timer 終止 | 在 run() 中捕獲所有異常,記錄日誌但不拋出,保證 Timer 存活 |
| 優雅關閉等待進行中任務 | contextDestroyed 中呼叫 timer.cancel() 後,可配合 CountDownLatch 等待執行緒結束 |
| Spring 環境整合 | 改用 @Scheduled 註解或 TaskScheduler Bean,由 Spring 容器管理生命週期 |
五、Timer vs ScheduledExecutorService 選擇指南
- Timer:單執行緒、API 簡單、適用輕量級、非關鍵任務、Java 1.3+ 相容
- ScheduledExecutorService:執行緒池、支援固定延遲/固定頻率、更好的異常處理、可監控、Java 5+ 標準選擇
六、結語
ServletContextListener 配合 Timer 是實現 Web 應用啟動/關閉自動化任務的經典模式,零依賴、輕量級、符合 Servlet 規範。掌握此模式,可滿足大多數定時掃描、資料同步、報表生成等背景處理需求。對於高可用、叢集或複雜排程場景,建議升級至 ScheduledExecutorService 或引入 Quartz、Spring Task 等專業排程框架。
- 上一篇文章: JBoss 整合 Hibernate 完整部署配置指南
- 下一篇文章: Java 常用資料型別轉換完全手冊:基本型別、字串與包裝類別互轉
Copyright ©
程式碼之家 All Rights Reserved