【声明】文章为本人学习时记录的笔记。 原课程地址:www.liaoxuefeng.com/wiki/154595…
一、前言
1、Listener是Java Web App中的一种事件监听机制,用于监听Web应用程序中产生的事件。
2、Servlet规范定义了很多种Listener接口,常用的Listener包括:
ServletContextListener:用于监听ServletContext的创建和销毁事件;HttpSessionListener:用于监听HttpSession的创建和销毁事件;ServletRequestListener:用于监听ServletRequest的创建和销毁事件;ServletContextAttributeListener:用于监听ServletContext属性的添加、修改和删除事件;HttpSessionAttributeListener:用于监听HttpSession属性的添加、修改和删除事件;ServletRequestAttributeListener:用于监听ServletRequest属性的添加、修改和删除事件。
3、Listener机制是基于观察者模式实现的,即当某个事件发生时,Listener会接收到通知并执行相应的操作。
二、目标
让我们的系统支持 HttpSessionListener,实现监听HttpSession的创建和销毁事件;
三、实现
uml类图:
1、和Servlet组件,Filter组件一样,我们也把Listener组件放在ServletContext中来统一维护。
public class ServletContextImpl implements ServletContext {
...
// 【listener】在ServletContext中管理Listener。
// ServletContextListener 用于监听ServletContext的创建和销毁事件
private List<ServletContextListener> servletContextListeners = null;
// 监听ServletContext属性的添加、修改和删除事件
private List<ServletContextAttributeListener> servletContextAttributeListeners = null;
// 用于监听ServletRequest的创建和销毁事件;
private List<ServletRequestListener> servletRequestListeners = null;
// 用于监听ServletRequest属性的添加、修改和删除事件。
private List<ServletRequestAttributeListener> servletRequestAttributeListeners = null;
// 用于监听HttpSession属性的添加、修改和删除事件;
private List<HttpSessionAttributeListener> httpSessionAttributeListeners = null;
// 用于监听HttpSession的创建和销毁事件;
private List<HttpSessionListener> httpSessionListeners = null;
...
}
2、实现ServletContext的addListener()接口,用于注册Listener。
@Override
public void addListener(Class<? extends EventListener> clazz) {
try {
addListener(clazz.newInstance());
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
@Override
public <T extends EventListener> void addListener(T t) {
if (t instanceof ServletContextListener listener) {
if (this.servletContextListeners == null) {
this.servletContextListeners = new ArrayList<>();
}
this.servletContextListeners.add(listener);
} else if (t instanceof ServletContextAttributeListener listener) {
if (this.servletContextAttributeListeners == null) {
this.servletContextAttributeListeners = new ArrayList<>();
}
this.servletContextAttributeListeners.add(listener);
} else if (t instanceof ServletRequestListener listener) {
if (this.servletRequestListeners == null) {
this.servletRequestListeners = new ArrayList<>();
}
this.servletRequestListeners.add(listener);
} else if (t instanceof ServletRequestAttributeListener listener) {
if (this.servletRequestAttributeListeners == null) {
this.servletRequestAttributeListeners = new ArrayList<>();
}
this.servletRequestAttributeListeners.add(listener);
} else if (t instanceof HttpSessionAttributeListener listener) {
if (this.httpSessionAttributeListeners == null) {
this.httpSessionAttributeListeners = new ArrayList<>();
}
this.httpSessionAttributeListeners.add(listener);
} else if (t instanceof HttpSessionListener listener) {
if (this.httpSessionListeners == null) {
this.httpSessionListeners = new ArrayList<>();
}
this.httpSessionListeners.add(listener);
} else {
throw new IllegalArgumentException("Unsupported listener: " + t.getClass().getName());
}
}
3、在合适的时机,触发这些Listener。
比如HttpSessionListener要监听Session的创建和销毁,那么就需要在Session创建和销毁的时候,进行对应的事件触发。
// 创建session的时候。
public HttpSession getSession(String sessionId) {
HttpSessionImpl session = sessions.get(sessionId);
if (session == null) {
// Session未找到,创建一个新的Session:
session = new HttpSessionImpl(this.servletContext, sessionId, inactiveInterval);
sessions.put(sessionId, session);
// tag 在这里触发session创建事件
this.servletContext.invokeHttpSessionCreated(session);
} else {
// Session已存在,更新最后访问时间:
session.lastAccessedTime = System.currentTimeMillis();
}
return session;
}
// 销毁的时候
public void remove(HttpSession session) {
this.sessions.remove(session.getId());
// 触发session销毁的事件
this.servletContext.invokeHttpSessionDestroyed(session);
}
4、定义我们自己的Listener。
这里比如我们目标中的HttpSessionListener
@WebListener
public class MyHttpSessionListener implements HttpSessionListener {
final Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void sessionCreated(HttpSessionEvent se) {
logger.info(">>> HttpSession created: {}", se.getSession());
// 自定义一些接收事件后的处理逻辑
doSomethine();
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
logger.info(">>> HttpSession destroyed: {}", se.getSession());
// 自定义一些接收事件后的处理逻辑
doSomethine();
}
}
5、最后在Connector中完成对Listener的注册。
public HttpConnector() throws IOException {
this.servletContext = new ServletContextImpl();
// 上下文注册 servlet 到context中的map
this.servletContext.initialize(List.of(IndexServlet.class, HelloServlet.class, LoginServlet.class, LogoutServlet.class));
// 上下文注册 filter 到context中的map
this.servletContext.initFilters(List.of(HelloFilter.class, LogFilter.class));
// 上下文注册 listener
List.of(MyHttpSessionListener.class).forEach(this.servletContext::addListener);
String host = "0.0.0.0";
int port = 8080;
this.httpServer = HttpServer.create(new InetSocketAddress(host, port), 0, "/", this);
// start http server
this.httpServer.start();
logger.info("http server started at {}:{}...", host, port);
}