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

Servlet 監聽器全解析:八大接口、生命週期事件與實戰應用模式

     編輯:Java 綜合教學

Servlet 監聽器全解析:八大接口、生命週期事件與實戰應用模式

Servlet 監聽器是 Web 應用事件模型的核心組件,通過**觀察者模式**監聽 ServletContext、HttpSession、ServletRequest 三大域對象的**生命週期**與**屬性變化**事件。本文系統梳理八大標準監聽器接口、註冊配置、兩大經典實戰場景 (在線人數統計、數據源初始化) 及最佳實踐。

一、八大標準監聽器接口速覽

接口監聽對象觸發事件核心方法
ServletContextListenerServletContext (應用級)初始化 / 銷毀contextInitialized/contextDestroyed
ServletContextAttributeListenerServletContext 屬性增 / 刪 / 改attributeAdded/attributeRemoved/attributeReplaced
HttpSessionListenerHttpSession (會話級)創建 / 失效sessionCreated/sessionDestroyed
HttpSessionActivationListener綁定到 Session 的對象鈍化 / 活化 (分布式遷移)sessionWillPassivate/sessionDidActivate
HttpSessionAttributeListenerSession 屬性增 / 刪 / 改attributeAdded/attributeRemoved/attributeReplaced
HttpSessionBindingListener綁定到 Session 的對象綁定 / 解綁valueBound/valueUnbound
ServletRequestListenerServletRequest (請求級)初始化 / 銷毀requestInitialized/requestDestroyed
ServletRequestAttributeListenerRequest 屬性增 / 刪 / 改attributeAdded/attributeRemoved/attributeReplaced

二、註冊配置:web.xml vs @WebListener

2.1 web.xml (傳統)

<listener>
    <listener-class>com.demo.listener.UserListener</listener-class>
</listener>
<listener>
    <listener-class>com.demo.listener.DataSourceListener</listener-class>
</listener>

2.2 @WebListener (Servlet 3.0+ 推薦)

@WebListener
public class UserListener implements HttpSessionBindingListener { ... }

優勢: 無需 XML、類掃描自動註冊、支援動態添加 (ServletContext.addListener())。

三、實戰場景一:在線人數統計 — HttpSessionBindingListener

核心思想: 實現 HttpSessionBindingListener 的對象被放入 Session 時自動觸發 valueBound,移除/失效時觸發 valueUnbound,**無需在 Listener 類中手動獲取 Session**。

package com.demo.listener;

import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;

public class UserListener implements HttpSessionBindingListener {
    // 被放入 Session 時調用
    public void valueBound(HttpSessionBindingEvent event) {
        OnlineCounter.increment(); // 線程安全計數器
        System.out.println("用戶上線:" + event.getName() + " 當前在線:" + OnlineCounter.getCount());
    }

    // 從 Session 移除/失效時調用
    public void valueUnbound(HttpSessionBindingEvent event) {
        OnlineCounter.decrement();
        System.out.println("用戶下線:" + event.getName() + " 當前在線:" + OnlineCounter.getCount());
    }
}

使用方式: 登入成功後 session.setAttribute("user", new UserListener()),**對象本身即監聽器**,極其優雅。

四、實戰場景二:應用啟動初始化數據源 — ServletContextListener

package com.demo.listener;

import javax.servlet.*;
import javax.naming.*;
import javax.sql.DataSource;

public class DataSourceListener implements ServletContextListener {
    public void contextInitialized(ServletContextEvent event) {
        ServletContext sc = event.getServletContext();
        try {
            Context ctx = new InitialContext();
            // JNDI 查找容器配置的數據源
            DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/mydb");
            // 存入應用域,全局可用
            sc.setAttribute("dataSource", ds);
            System.out.println("DataSource 初始化完成並綁定到 ServletContext");
        } catch (NamingException e) {
            throw new RuntimeException("DataSource 初始化失敗", e);
        }
    }

    public void contextDestroyed(ServletContextEvent event) {
        // 清理資源 (如關閉連接池)
        ServletContext sc = event.getServletContext();
        DataSource ds = (DataSource) sc.getAttribute("dataSource");
        if (ds instanceof org.apache.commons.dbcp2.BasicDataSource) {
            try { ((org.apache.commons.dbcp2.BasicDataSource) ds).close(); } catch (Exception ignored) {}
        }
    }
}

Servlet 使用:

DataSource ds = (DataSource) getServletContext().getAttribute("dataSource");
try (Connection conn = ds.getConnection()) {
    // 業務邏輯
}

五、監聽器執行順序與線程安全

  1. 初始化順序: 按 web.xml 或掃描順序聲明順序調用 contextInitialized;銷毀逆序。
  2. 線程安全: contextInitialized 由容器單線程啟動時調用,安全;sessionCreated/requestInitialized **多線程併發調用**,操作共享數據 (如計數器) **必須用原子類或同步**。
  3. 異常處理: contextInitialized 拋出異常將導致應用啟動失敗;其他監聽器異常僅記錄日誌不影響主流程。

六、最佳實踐清單

  • 職責單一: 一個監聽器只做一件事 (如只初始化數據源、只統計在線人數)。
  • 優先 @WebListener: 現代項目拋棄 web.xml 監聽器註冊。
  • 避免重業務邏輯: 監聽器屬於基礎設施層,複雜業務應委託給 Service 層異步處理。
  • 資源清理要在 Destroyed: 連接池、線程池、緩存客戶端必須在 contextDestroyed 關閉,防洩漏。
  • 分布式環境: 單機 Session 監聽器失效,需結合 Redis + Session 共享方案 (Spring Session) 實現集群在線人數統計。

七、總結

Servlet 監聽器是 Web 容器事件總線的**官方接入點**。掌握八大接口的**監聽對象、觸發時機、核心方法**,配合 @WebListener 註解,能優雅解決:應用啟動初始化、在線用戶統計、請求鏈路追蹤、屬性變更審計、分布式 Session 遷移 等橫切關注點。將監聽器作為「基礎設施代碼」而非「業務代碼」編寫,是架構整潔的關鍵。

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