Hello,Web Listener
这是一篇供笔记性质的博文,仅用于帮助基础知识的记忆。
定义
web 监听器是 Servlet 规范中定义的一种特殊类,可以监听客户端的请求,也可以监听服务端的操作。监听的对象包括:ServletContent、HttpSession 以及 ServletRequest 等域对象。这三个对象,分别对应 application、session 和 request 对象,可以监听它们的创建、销毁以及属性变化的事件,并在这些事件发生前、发生后,做一些必要的处理。
用途
-
统计在线人数和在线用户
-
系统启动时加载初始化信息(缓存、公用链接等)
-
统计网站访问量
-
跟 spring 结合
创建一个 web 监听器
相关源码请见 jsp-basic
-
创建一个新的 listener 包,包下创建一个 implements 于 ServletContextListener 的类,类下实现两个方法,contextInitialized 和 contextDestroyed。具体例子如:
package com.liumapp.jspbasic.listener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; /** * Created by liumapp on 6/1/17. * E-mail:liumapp.com@gmail.com * home-page:http://www.liumapp.com */public class FirstListener implements ServletContextListener{ public void contextInitialized(ServletContextEvent servletContextEvent) { System.out.println("initialized"); } public void contextDestroyed(ServletContextEvent servletContextEvent) { System.out.println("destroyed"); } }
-
配置 web.xml 文件,添加如下代码:
<listener> <listener-class>com.liumapp.jspbasic.listener.FirstListenerlistener-class> <listener>
-
到此,第一个 web 监听器创建完成
监听器启动顺序
-
多个监听器的启动顺序按照 web.xml 中的加载顺序来定义
-
优先级:监听器 > 过滤器 > Servlet
监听器的分类
ServletContext
用于监听应用程序环境对象的事件监听器
HttpSession
用于监听用户会话对象的事件监听器
ServletRequest
用于监听请求消息对象的事件监听器
按事件划分
监听域对象自身的创建和销毁的事件监听器
-
ServletContext->ServletContextListener,在项目中,可以定义多个 ServletContextListener,但只会有一个 ServletContext 对象。一般用于做定时器,或者加载全局属性对象,缓存、数据库连接等。我们创建第一个 web 监听器用到的就是 ServletContextListener。
-
HttpSession->HttpSessionListener,具体请看下方代码:
package com.liumapp.jspbasic.listener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; /** * Created by liumapp on 6/2/17. * E-mail:liumapp.com@gmail.com * home-page:http://www.liumapp.com */ public class FirstHttpSessionListener implements HttpSessionListener { public void sessionCreated(HttpSessionEvent httpSessionEvent) { System.out.println("sessionCreated"); } /** * 配置文件中设置了session的超时时间为1分钟,但实际所需要的时间是1分半才会执行sessionDestroy. * @param httpSessionEvent */ public void sessionDestroyed(HttpSessionEvent httpSessionEvent) { System.out.println("sessionDestroyed"); } }
-
ServletRequest->ServletRequestListener,在项目中,可以定义多个 ServletRequestListener,但只会有一个 ServletRequest 对象。具体代码如下所示
package com.liumapp.jspbasic.listener; import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestListener; /** * Created by liumapp on 6/2/17. * E-mail:liumapp.com@gmail.com * home-page:http://www.liumapp.com */ public class FirstServletRequestListener implements ServletRequestListener { public void requestDestroyed(ServletRequestEvent servletRequestEvent) { System.out.println("requestDestroyed"); } public void requestInitialized(ServletRequestEvent servletRequestEvent) { String name = servletRequestEvent.getServletRequest().getParameter("name"); // by get method System.out.println("requestInitialized and name is :" + name); } }
监听域对象中的属性的增加和删除的事件监听器
-
ServletContext->ServletContextAttributeListener
-
HttpSession->HttpSessionAttributeListener
-
ServletRequest->ServletRequestAttributeListener
上面三个监听器的用法都是一样的,代码的例子就举一个吧,下面的例子表示,监听器会监听属性的创建、删除和替换这三个事件,然后触发事件。
package com.liumapp.jspbasic.listener;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
/**
* Created by liumapp on 6/2/17. * E-mail:liumapp.com@gmail.com * home-page:http://www.liumapp.com */
public class FirstServletContextAttributeListener implements ServletContextAttributeListener {
public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("servletContextAttribute added , name is : " + servletContextAttributeEvent.getName());
}
public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("servletContextAttribute removed , name is : " + servletContextAttributeEvent.getName());
}
public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("servletContextAttribute replaced , name is : " + servletContextAttributeEvent.getName());
}
}
监听绑定到 HttpSession 域中的某个对象的的状态的事件监听器
HttpSession 中的对象状态分为:
-
绑定-> 解除绑定
绑定就是通过 session 的 setAttribute 添加一个 session 属性,解除绑定就是通过 removeAttribute 删除一个 session 属性。
-
钝化-> 活化
钝化就是将 session 持久性的保存在 database 或者 redis 上面,活化就是将 session 从 database 或者 redis 上面恢复到原有的保存方式。
session 钝化机制
把服务器中不经常使用的 session 对象暂时序列化到文件系统或是数据库系统中,当被使用时反序列化到内存中,整个过程由服务器自动完成。
Tomcat 中的两种 session 钝化管理机制
-
org.apache.catalina.session.StandardManager
- 当 Tomcat 服务器被关闭或者重启时,Tomcat 服务器会将当前内存中的 Session 对象钝化到服务器文件系统中;
- 当 Web 应用程序被重新加载时,内存中的 Session 对象也会被钝化到服务器的文件系统中;
- 钝化后的文件被保存在 Tomcat 安装路径/work/Catalina/hostname/applicationname/SESSION.ser
-
org.apache.catalina.session.PersistentManager
- 首先在钝化的基础上进行了扩张。第一种情况如上面的第一点,第二种情况如上面的第二点,第三种情况,可以配置主流内存的 Session 对象数目,将不常使用的 Session 对象保存到文件系统或者数据库,当用时再加载;
- 默认情况下,Tomcat 提供两个钝化驱动类:org.apache.catalina.FileStore 和 org.apache.catalina.JdbcStore。
好像扯远了......
现在回到监听器上来......
请注意,以下两个监听器不需要在 web.xml 进行注册。
-
HttpSessionBindingListener
- 绑定:valueBound 方法
- 解除绑定:valueUnbound 方法
实现这个接口的时候,并不是创建一个 Listener 来实现,而是创建一个普通的 JavaBean 来实现。因为最终修改的是一个普通的对象的状态,而不是监听器的状态。这里我们举的例子如下:
package com.liumapp.jspbasic.entity; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; /** * Created by liumapp on 6/2/17. * E-mail:liumapp.com@gmail.com * home-page:http://www.liumapp.com */ public class User implements HttpSessionBindingListener { private String userName; private String passWord; public void valueBound(HttpSessionBindingEvent httpSessionBindingEvent) { System.out.println("user valueBound , name is : " + httpSessionBindingEvent.getName()); } public void valueUnbound(HttpSessionBindingEvent httpSessionBindingEvent) { System.out.println("user valueUnBound , name is : " + httpSessionBindingEvent.getName()); } public String getUserName() { return userName; } public String getPassWord() { return passWord; } public void setUserName(String userName) { this.userName = userName; } public void setPassWord(String passWord) { this.passWord = passWord; } }
随后我们通过下面的两行代码即可实现 bound 和 unbound 事件的触发:
request.getSession().setAttribute("currentUser" , new com.liumapp.jspbasic.entity.User()); request.getSession().removeAttribute("currentUser");
-
HttpSessionActivationListener
- 钝化:sessionWillPassivate 方法
- 活化:sessionDidActive 方法
代码如下所示:
package com.liumapp.jspbasic.entity; import sun.plugin2.message.Serializer; import javax.servlet.http.HttpSessionActivationListener; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; import javax.servlet.http.HttpSessionEvent; import java.io.Serializable; /** * Created by liumapp on 6/2/17. * E-mail:liumapp.com@gmail.com * home-page:http://www.liumapp.com */ public class User implements HttpSessionBindingListener , HttpSessionActivationListener , Serializable { private String userName; private String passWord; public void valueBound(HttpSessionBindingEvent httpSessionBindingEvent) { System.out.println("user valueBound , name is : " + httpSessionBindingEvent.getName()); } public void valueUnbound(HttpSessionBindingEvent httpSessionBindingEvent) { System.out.println("user valueUnBound , name is : " + httpSessionBindingEvent.getName()); } public String getUserName() { return userName; } public String getPassWord() { return passWord; } public void setUserName(String userName) { this.userName = userName; } public void setPassWord(String passWord) { this.passWord = passWord; } //钝化 public void sessionWillPassivate(HttpSessionEvent httpSessionEvent) { System.out.println("sessionWillPassivate : " + httpSessionEvent.getSource()); } //活化 public void sessionDidActivate(HttpSessionEvent httpSessionEvent) { System.out.println("sessionDidActivate : " + httpSessionEvent.getSource()); } }
我们进入 init 页面后停止 tomcat 服务器,session 会自动序列化之后存入文件系统中,相关信息如下所示:
sessionWillPassivate : org.apache.catalina.session.StandardSessionFacade@4666d1cf
第二次启动 Tomcat 之后,session 信息将会反序列化然后被加载,我们可以在 index.jsp 看到输入的 session 信息,同时请注意,这里还需要引入 Serializable 的接口实现,不然无法成功反序列化。
上面的描述都是 Tomcat 的第一种 session 钝化管理机制,那么第二种 PersistentManager 如何使用呢?
首先我们进入 Tomcat/conf 目录,打开 context.xml 文件,找到如下的代码
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!--
<Manager pathname="" />
-->
把 manager 的 pathname 设置为 FileStore 或者 JdbcStore,两者类型的详细信息下回分解。
Servlet3.0 下面监听器的使用
前文的描述都是针对 Servlet2.5 版本来进行的,那么在 Servlet3.0 下面,我们需要做的,就是不需要在 web.xml 下面进行 listener 的任何注解,只需要在 listener 类的前面,加一个注解即可,如下:
@WebListener("this is my web listener")
class ....
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于