JavaWeb—监听器Listener
1.简介
Listener是Servlet的监听器,Servlet 监听器用于监听一些重要事件的发生,监听器对象在事情发生前、发生后可以做一些必要的处理。
JavaWeb里面的listener是通过观察者设计模式进行实现的。
观察者模式又叫发布订阅模式或者监听器模式。在该模式中有两个角色:观察者和被观察者(通常也叫做主题)。观察者在主题里面注册自己感兴趣的事件,当这个事件发生时,主题会通过回调接口的方式通知观察者。
举个生活中的例子:订阅报纸。任何一个家庭或个人都可以向报社订阅报纸。这里报社就是“主题”,家庭就是“观察者”。比如家庭需要订阅明天早晨的报纸,这个就是“事件”。到了第二天早晨,报纸生产出来了,这个就是“事件发生”。当事件发生时,送报员将报纸送到家庭的信箱里面,这里的信箱就是“回调接口”。
对于JavaWeb里面的监听器,Servlet规范定义了一些列的Listener接口类,通过接口类的方式将事件暴露给应用程序,应用程序如果想监听其感兴趣的事件,那么不必去直接注册对应的事件,而是编写自己的listener实现相应的接口类,并将自己的listener注册到servlet容器。当程序关心的事件发生时,servlet容器会通知listener,回调listener里面的方法。这里自定义的listener就是观察者,servlet容器就是主题。
2.分类
现在我们分析下,servlet规范为我们定义了哪些事件。更准确的说是定义了哪些监听接口。下面的介绍都是以servlet3.0规范为准。
servlet3.0为我们提供了8个监听器接口,按照它们的作用域来划分的话可以分为三类:
1.servlet上下文相关监听接口:
- ServletContextListener
- ServletContextAttributeListener
2.http session相关监听接口:
- HttpSessionListener
- HttpSessionActivationListener
- HttpSessionAttributeListener
- HttpSessionBindingListener
3.servlet request相关监听接口:
- ServletRequestListener
- ServletRequestAttributeListener
3.Java编写Listener实例
Listener编写分为两步:
- 编写自己的listener,实现特定的Listener接口
- 在web.xml里面注册自己的listener(也可以通过注解的方式,道理是一样的)
ListenerDemo.java(这里继承ServletContextListener接口):
public class ListenerDemo implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent servletContextEvent) { System.out.println("----------ServletContextListener.contextInitialized-----------"); } @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { System.out.println("----------ServletContextListener.contextDestroyed----------"); } }
web.xml:
<listener> <listener-class>com.xzh.ListenerDemo</listener-class> </listener>
效果图:
注意:结果中可以看到listener比filter先执行。
4.源码分析
4.1 ServletContextListener
public interface ServletContextListener extends EventListener { void contextInitialized(ServletContextEvent var1); void contextDestroyed(ServletContextEvent var1); }
servlet上下文监听器接口,对应着两个事件:servlet上下文初始化事件和servlet上下文即将关闭事件。
当web应用初始化的时候,servlet容器会构造ServletContextEven实例,并回调contextInitialize方法。当servlet上下文即将关闭时,一般是关闭服务器之前,servlet容器会构造ServletContextEven实例,并回调contextDestroyed方法。这里需要注意的是,contextDestroyed方法的执行会在所有的servlet和filter执行完destroy方法之后。
4.2 ServletContextAttributeListener
public interface ServletContextAttributeListener extends EventListener { void attributeAdded(ServletContextAttributeEvent var1); void attributeRemoved(ServletContextAttributeEvent var1); void attributeReplaced(ServletContextAttributeEvent var1); }
当servlet上文属性发生增、删、改的时候,servlet容器构造ServletContextAttributeEvent事件对象,分别回调attributeAdded、attributeRemoved、attributeReplaced方法。
这里需要注意的是attributeReplaced方法,当属性的值被替换的时候回调。这个时候如果调用ServletContextAttributeEvent.getValue()方法返回的是替换之前的属性值。
4.3 HttpSessionListener
public interface HttpSessionListener extends EventListener { void sessionCreated(HttpSessionEvent var1); void sessionDestroyed(HttpSessionEvent var1); }
当session被创建和销毁的时候,servlet容器构造HttpSessionEvent事件对象,并回调sessionCreated和sessionDestroyed方法。
4.4 HttpSessionActivationListener
public interface HttpSessionActivationListener extends EventListener { void sessionWillPassivate(HttpSessionEvent var1); void sessionDidActivate(HttpSessionEvent var1); }
当session将要钝化或已被激活时,servlet容器构造HttpSessionEvent事件对象,回调sessionWillPassivate和sessionDidActivate方法。
这里解释下钝化和激活:钝化是指服务器内存不够了或者session的活动超时时间到了,把最近不活动的session序列化到磁盘。激活是指某个钝化的session又被访问了,从磁盘将session反序列化到内存。
这里可以看出要想钝化和激活,首先session得可序列化和反序列化。同时我们在编程过程中,session尽量用String、Integer等简单的对象,尽量不要用list、map等集合。3.5
4.5 HttpSessionAttributeListener
public interface HttpSessionAttributeListener extends EventListener { void attributeAdded(HttpSessionBindingEvent var1); void attributeRemoved(HttpSessionBindingEvent var1); void attributeReplaced(HttpSessionBindingEvent var1); }
当session属性发生增、删、改的时候,servlet容器构造HttpSessionBindingEvent事件对象,分别回调attributeAdded、attributeRemoved、attributeReplaced方法。
这里需要注意的是attributeReplaced方法,当属性的值被替换的时候回调。这个时候如果调用ServletContextAttributeEvent.getValue()方法返回的是替换之前的属性值。
当调用session的invalidate方法或者session失效时,也会回调attributeRemoved方法。
4.6 HttpSessionBindingListener
public interface HttpSessionBindingListener extends EventListener { void valueBound(HttpSessionBindingEvent var1); void valueUnbound(HttpSessionBindingEvent var1); }
这个监听器也是监听session的属性变化。当session属性发生增和删,也就是属性值绑定和属性值解绑的时候,servlet容器构造HttpSessionBindingEvent事件对象,分别回调valueBound、valueUnbound方法。
这么一看和HttpSessionAttributeListener没什么区别,其实不是这样。两者有个本质的区别就是事件触发的条件。
当session的属性有任何的变化,servlet容器都会通知HttpSessionAttributeListener。但是对于HttpSessionBindingListener,只有当绑定或解绑的属性值是监听器的实例时,servlet容器才会通知。
4.7 ServletRequestListener
public interface ServletRequestListener extends EventListener { void requestDestroyed(ServletRequestEvent var1); void requestInitialized(ServletRequestEvent var1); }
当请求初始化或者销毁时,即客户端请求进入web应用(进入servlet或者第一个filter)或web应用返回响应给客户端(退出servlet或者第一个filter)。servlet容器构造ServletRequestEvent实例,回调requestInitialized和requestDestroyed方法。
4.8 ServletRequestAttributeListener
public interface ServletRequestAttributeListener extends EventListener { void attributeAdded(ServletRequestAttributeEvent var1); void attributeRemoved(ServletRequestAttributeEvent var1); void attributeReplaced(ServletRequestAttributeEvent var1); }
当请求的属性发生增、删、改的时候,servlet容器构造ServletRequestAttributeEvent事件对象,分别回调attributeAdded、attributeRemoved、attributeReplaced方法。
这里需要注意的是attributeReplaced方法,当属性的值被替换的时候回调。这个时候如果调用ServletRequestAttributeEvent.getValue()方法返回的是替换之前的属性值。
参考:
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步