1.监听器的概念
监听器(Listener),是Servlet的监听器,它可以监听客户端的请求、服务端的操作等。通过监听器,可以自动激发一些操作,比如监听在线的用户的数量。
2.监听器的用途
- 统计在线用户
- 系统启动时加载初始化信息
- 统计网站访问量
- 跟spring结合
3.创建一个监听器的步骤
- 创建一个实现监听器接口的类
- 配置web.xml或使用注解
监听器分三类共八种,其中有两个特殊的监听器创建步骤不是上面所讲的那样,后面我们会讲。
配置web.xml
<listener>
<listener-class>监听器的路径</listener-class>
</listener>
使用注解
直接在监听器类的开头使用@WebListener即可。
4.监听器的启动顺序(对于同类监听器)
- 若在web.xml中配置有多个监听器,则按照配置的顺序一一加载。(如果使用注解则无法定义顺序)
- 若在web.xml中有过滤器,监听器和Servlet,则优先级监听器 > 过滤器 > Servlet。
5.监听器的分类
按监听的对象划分:
- 用于监听应用程序环境对象(ServletContext)的事件监听器
- 用于监听用户会话对象(HttpSession)的事件监听器
- 用于监听请求消息对象(ServletRequest)的事件监听器
按监听的事件划分:
- 用于监听域对象自身的创建和销毁的事件监听器
- 用于监听域对象中属性的增加和删除的事件监听器
- 用于监听绑定到HttpSession域中的某个对象的状态的事件监听器
在创建的时候,会让我们选择是哪一类监听器
下面我们按照监听的事件来详细说一说这些监听器。
监听域对象自身的创建和销毁的事件监听器
(1)ServletContetx———————>ServletContextListener
ServletContextListener接口源码如下
package javax.servlet;
import java.util.EventListener;
public interface ServletContextListener extends EventListener {
// 初始化时调用
public void contextInitialized ( ServletContextEvent sce );
// 销毁时调用
public void contextDestroyed ( ServletContextEvent sce );
}
该监听器在启动tomcat后,就会进行加载。通过contextInitialized 方法的参数,可以获取初始化参数。一个web应用程序中只有一个ServletContext对象,一个ServletContext对象可以对应多个ServletContextListener。
该监听器的主要用途是:定时器、全局属性对象。
(2)HttpSession——————————–>HttpSessionListener
HttpSessionListener接口的源码如下:
package javax.servlet.http;
import java.util.EventListener;
public interface HttpSessionListener extends EventListener {
// 客户端第一次开启一个网页时调用
public void sessionCreated ( HttpSessionEvent se );
// session过期时调用
public void sessionDestroyed ( HttpSessionEvent se );
}
该监听器在启动tomcat后,用户第一次打开网页,就会产生一个session,可以在web.xml中设置session过期时间,当session过期时,就调用监听器的销毁方法。
一个web应用程序中可以有多个HttpSession对象,一个HttpSession对象可以对应多个HttpSessionListener。
主要用途:统计在线人数、记录访问日志。
(3)ServletRequest——————————–>ServletRequestListener
ServletRequestListener接口的源码如下
package javax.servlet;
import java.util.EventListener;
public interface ServletRequestListener extends EventListener {
// 请求完成后立即销毁
public void requestDestroyed ( ServletRequestEvent sre );
// 用户发送请求时调用该方法
public void requestInitialized ( ServletRequestEvent sre );
}
该监听器在启动tomcat后,用户只要向服务器发送了请求,就会触发(比如用户请求打开某一个网页),请求完成后销毁(当请求的网页加载完成后)。
主要用途:读取参数、记录访问历史
监听域对象中属性增加和删除的监听器
(1)ServletContext————————>ServletContextAttributeListener
ServletContextAttributeListener接口的源码如下
package javax.servlet;
import java.util.EventListener;
public interface ServletContextAttributeListener extends EventListener {
public void attributeAdded(ServletContextAttributeEvent scab);
public void attributeRemoved(ServletContextAttributeEvent scab);
public void attributeReplaced(ServletContextAttributeEvent scab);
}
(2)HttpSession—————————->HttpSessionAttributeListener
HttpSessionAttributeListener接口的源码如下
package javax.servlet.http;
import java.util.EventListener;
public interface HttpSessionAttributeListener extends EventListener {
public void attributeAdded ( HttpSessionBindingEvent se );
public void attributeRemoved ( HttpSessionBindingEvent se );
public void attributeReplaced ( HttpSessionBindingEvent se );
}
(3)ServletRequest————————>ServletRequestAttributeListener
ServletRequestAttributeListener接口的源码如下
package javax.servlet;
import java.util.EventListener;
public interface ServletRequestAttributeListener extends EventListener {
public void attributeAdded(ServletRequestAttributeEvent srae);
public void attributeRemoved(ServletRequestAttributeEvent srae);
public void attributeReplaced(ServletRequestAttributeEvent srae);
}
上述三个接口里的方法都一样,attributeAdded方法在添加属性时调用,attributeRemoved方法在移除属性时调用,attributeReplaced方法在属性替换时调用。看看下面的代码
// 这里会分别调用它们的attributeAdded方法
request.setAttribute("requestname", "requestvalue");
request.getSession().setAttribute("sessionname", "sessionvalue");
request.getSession().getServletContext().setAttribute("contextname", "contextvalue");
// 触发ServletRequestAttributeListener的attributeReplaced方法
request.setAttribute("requestname", "requestvalue");
// 这里会分别调用它们的attributeRemoved方法
request.removeAttribute("requestname");
request.getSession().removeAttribute("sessionname");
request.getSession().getServletContext().removeAttribute("contextname");
监听绑定到HttpSession域中的某个对象的状态的事件监听器(该类监听器不用在web.xml中配置)
(1)HttpSessionBindingListener:绑定(valueBound方法)————->解除绑定(valueUnbound方法)
HttpSessionBindingListener接口的源码如下
package javax.servlet.http;
import java.util.EventListener;
public interface HttpSessionBindingListener extends EventListener {
// 绑定
public void valueBound(HttpSessionBindingEvent event);
// 解除绑定
public void valueUnbound(HttpSessionBindingEvent event);
}
所谓对session进行数据绑定,就是调用session.setAttribute()把HttpSessionBindingListener保存进session中。
使用SetAttribute(“xxx”, 实现了该接口的类的实例对象)。比如request.getSession().setAttribute(“test”, new Test());就把Test的对象绑定到了HttpSession域中(调用valueBound方法)。
valueUnbound的触发条件是以下三种情况:
- 执行session.invalidate()时。
- session超时,自动销毁时。
- 执行session.setAttribute(“onlineUserListener”,
“其他对象”);或session.removeAttribute(“onlineUserListener”);将listener从session中删除时。
HttpSessionBindingListener和HttpSessionListener之间的最大区别:HttpSessionListener只需要设置到web.xml中就可以监听整个应用中的所有session。HttpSessionBindingListener必须实例化后放入某一个session中,才可以进行监听。
从监听范围上比较,HttpSessionListener设置一次就可以监听所有session,HttpSessionBindingListener通常都是一对一的。
正是这种区别成就了HttpSessionBindingListener的优势,我们可以让每个listener对应一个username,这样就不需要每次再去session中读取username,进一步可以将所有操作在线列表的代码都移入listener,更容易维护。
(2)HttpSessionActivationListener:钝化(sessionWillPassivate方法)—————–>活化(SessionDidActivate方法)
HttpSessionActivationListener接口的源码如下
package javax.servlet.http;
import java.util.EventListener;
public interface HttpSessionActivationListener extends EventListener {
public void sessionWillPassivate(HttpSessionEvent se);
public void sessionDidActivate(HttpSessionEvent se);
}
注意:实现此接口的同时,还需实现Serializable接口。活化(从硬盘到内存,序列化)和钝化(从内存到硬盘,反序列化)。
其实就是在用户访问的时候,假如服务器突然关闭了,这个时候,用户的session就不存在了,假如是购物网站,也就相当于,用户好不容易选好的物品,刚刚添加到购物车,结果,因为服务器的突然关闭一下,什么都没了,这样很不好,于是我们就需要实现会话的持久化。
钝化和活化可以让我们在重新启动服务器之后用户的session还在服务器中存在!即用户session的东西还全部在。因为服务器在关闭的时候把用户的session存储到硬盘了(钝化),保存在tomcat目录下的work->Catalina->localhost->项目名->SESSION.ser,在重新启动服务器之后,我们又从硬盘中恢复到内存中!(注意,只要用户还没关闭浏览器,那个session会一直存在用户的客户端的)。启动后,用户的信息就不会丢失!
好了,监听器的总结就到这里了。