首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Servlet 容器監聽器實作:啟動/關閉自動化任務排程

     編輯:Java 相關知識

在 Web 應用中,常需在應用啟動時啟動背景任務(如定時掃描、資料同步、快取預熱),在關閉時優雅停止。Servlet 規範提供 javax.servlet.ServletContextListener 介面,配合 java.util.Timer 即可輕鬆實現容器級的生命週期監聽與任務排程。本文以簡訊回覆監聽為例,示範完整實作模式。

一、核心介面與生命週期

二、完整實作範例:簡訊回覆監聽器

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(),無需額外配置。

四、進階實務考量

方法觸發時機典型用途
contextInitialized(ServletContextEvent)Servlet 容器啟動、Web 應用部署完成初始化資源、啟動排程任務、載入設定檔、建立連線池
contextDestroyed(ServletContextEvent)Servlet 容器關閉、Web 應用卸載釋放資源、停止排程任務、關閉連線池、記錄關閉日誌
議題建議做法
任務執行時間超過間隔使用 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 等專業排程框架。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved