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 ....