在開發 Java Web 應用時,使用 HttpSessionListener 與 HttpSessionAttributeListener 監聽 Session 的建立、銷毀及屬性變更,是常見的會話管理手段。然而,若在類別宣告時遺漏實作介面,會導致對應的監聽方法完全不被容器調用,且不拋出任何異常,極難排查。
package cn.lang.any.listener;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class AmpList implements ServletContextListener, HttpSessionListener /* 遺漏 HttpSessionAttributeListener */ {
private ServletContext application = null;
public void contextInitialized(ServletContextEvent sce) {
this.application = sce.getServletContext();
this.application.setAttribute("alluser", new ArrayList());
}
public void sessionCreated(HttpSessionEvent se) { }
public void sessionDestroyed(HttpSessionEvent se) {
List l = (List) this.application.getAttribute("alluser");
String value = (String) se.getSession().getAttribute("uname");
l.remove(value);
this.application.setAttribute("alluser", l);
}
// 以下屬性監聽方法因介面未實作,永不會被調用
public void attributeAdded(HttpSessionBindingEvent se) {
List lis = (List) this.application.getAttribute("alluser");
lis.add(se.getValue());
this.application.setAttribute("alluser", lis);
}
public void attributeRemoved(HttpSessionBindingEvent se) { }
public void attributeReplaced(HttpSessionBindingEvent se) { }
public void contextDestroyed(ServletContextEvent sce) { }
}
session.setAttribute("uname", "xxx") 時,attributeAdded 不執行,導致 application 範圍的 alluser 清單未同步更新。類別宣告 implements ServletContextListener, HttpSessionListener,缺少 HttpSessionAttributeListener。Servlet 容器在部署階段掃描監聽器時,僅註冊已實作介面對應的事件;未實作的介面方法視同不存在,故不納入通知鏈。
public class AmpList implements ServletContextListener, HttpSessionListener, HttpSessionAttributeListener {
// ... 原有方法保持不變
}
補上介面後重新部署,屬性監聽即刻生效。
implements 子句。org.apache.catalina.core.ApplicationContext 為 FINE 級別,觀察監聽器註冊情況。這是一個典型的「編譯通過、執行無錯、功能失效」的低級錯誤。Java 的介面機制要求宣告與實作嚴格對應,任何遺漏都會導致對應功能靜默失效。養成「先寫介面、再實作方法、最後核對宣告」的習慣,可有效避免此類問題。