定義:專門監聽其他對象事件或狀態變化,並即時響應處理的對象。本質是實現特定介面的普通 Java 類。
事件處理模型三要素:
遵循嚴格事件模型設計 Person 類:
// 事件對象:封裝事件源
class Event {
private final Person source;
Event(Person source) { this.source = source; }
Person getSource() { return source; }
}
// 監聽器介面:定義回調契約
interface PersonListener {
void doEat(Event e);
void doRun(Event e);
}
// 事件源:管理監聽器註冊與事件分發
class Person {
private PersonListener listener;
public void registerListener(PersonListener l) { this.listener = l; }
public void eat() {
if (listener != null) listener.doEat(new Event(this));
}
public void run() {
if (listener != null) listener.doRun(new Event(this));
}
}
// 使用
Person p = new Person();
p.registerListener(new PersonListener() {
public void doEat(Event e) { System.out.println(e.getSource() + " 在吃飯"); }
public void doRun(Event e) { System.out.println(e.getSource() + " 在跑步"); }
});
p.eat(); // 輸出: Person@xxx 在吃飯
此模式正是 JavaBean 事件模型與 Servlet 監聽器的理論基礎。
Servlet 監聽器專門監聽三大域對象的生命週期與屬性變化:
| 域對象 | 生命週期監聽 | 屬性變化監聽 | 特殊狀態監聽 |
|---|---|---|---|
| ServletContext | ServletContextListener | ServletContextAttributeListener | — |
| HttpSession | HttpSessionListener | HttpSessionAttributeListener | HttpSessionBindingListener HttpSessionActivationListener |
| ServletRequest | ServletRequestListener | ServletRequestAttributeListener | — |
@WebListener // Servlet 3.0+ 註解註冊,替代 web.xml
public class AppContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext ctx = sce.getServletContext();
System.out.println("【應用啟動】ServletContext 創建: " + ctx);
// 典型用途:初始化連接池、載入配置、啟動定時任務
ctx.setAttribute("appStartTime", System.currentTimeMillis());
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("【應用關閉】ServletContext 銷毀");
// 典型用途:關閉連接池、停止線程池、釋放資源
}
}
觸發時機:
@WebListener
public class SessionTracker implements HttpSessionListener {
private static final AtomicInteger activeSessions = new AtomicInteger(0);
@Override
public void sessionCreated(HttpSessionEvent se) {
HttpSession session = se.getSession();
int count = activeSessions.incrementAndGet();
System.out.println("【Session創建】ID=" + session.getId() + " 當前活躍=" + count);
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
int count = activeSessions.decrementAndGet();
System.out.println("【Session銷毀】剩餘活躍=" + count);
}
}
銷毀觸發條件:
web.xml 配置 <session-timeout>30</session-timeout>(分鐘)session.invalidate()
@WebListener
public class RequestTracer implements ServletRequestListener {
@Override
public void requestInitialized(ServletRequestEvent sre) {
HttpServletRequest req = (HttpServletRequest) sre.getServletRequest();
long start = System.nanoTime();
req.setAttribute("requestStartTime", start);
System.out.println("【請求開始】" + req.getRequestURI() + " from " + req.getRemoteAddr());
}
@Override
public void requestDestroyed(ServletRequestEvent sre) {
HttpServletRequest req = (HttpServletRequest) sre.getServletRequest();
Long start = (Long) req.getAttribute("requestStartTime");
long cost = System.nanoTime() - (start != null ? start : 0);
System.out.println("【請求結束】" + req.getRequestURI() + " 耗時=" + cost/1_000_000 + "ms");
}
}
觸發頻率:每次 HTTP 請求創建 Request,響應提交後銷毀。
// 以 ServletContext 為例,其他域同理
@WebListener
public class ContextAttrWatcher implements ServletContextAttributeListener {
@Override public void attributeAdded(ServletContextAttributeEvent scae) {
log("新增", scae.getName(), scae.getValue());
}
@Override public void attributeRemoved(ServletContextAttributeEvent scae) {
log("移除", scae.getName(), scae.getValue());
}
@Override public void attributeReplaced(ServletContextAttributeEvent scae) {
log("替換", scae.getName(), "舊值=" + scae.getValue() + " 新值=" + scae.getServletContext().getAttribute(scae.getName()));
}
private void log(String op, String name, Object val) {
System.out.println("【Context屬性" + op + "】" + name + "=" + val);
}
}
valueBound/valueUnbound,無需在 web.xml 註冊willPassivate/didActivate| 方式 | 適用版本 | 配置位置 | 優缺點 |
|---|---|---|---|
| web.xml | Servlet 2.5+ | <listener><listener-class>...</listener> | 通用、與代碼分離 |
| @WebListener | Servlet 3.0+ | 類上註解 | 簡潔、掃描啟動稍慢 |
| 動態註冊 | Servlet 3.0+ | ServletContextListener 中 sce.getServletContext().addListener() | 運行時動態決定 |
監聽器是 JavaWeb 應用的「神經系統」,掌握其生命週期觸發點與屬性感知機制,能優雅實現:應用啟動初始化、在線用戶統計、請求鏈路追蹤、分布式 Session 同步等核心功能。建議配合 Filter、AsyncListener 共同構建完整的 Web 基礎設施層。