一、监听域对象中属性的变更的监听器
域对象中属性的变更的事件监听器就是用来监听 ServletContext, HttpSession, HttpServletRequest 这三个对象中的属性变更信息事件的监听器。
这三个监听器接口分别是ServletContextAttributeListener, HttpSessionAttributeListener 和ServletRequestAttributeListener,这三个接口中都定义了三个方法来处理被监听对象中的属性的增加,删除和替换的事件,同一个事件在这三个接口中对应的方法名称完全相同,只是接受的参数类型不同。
1.1、ServletContextAttributeListener监听器案例
BListener.java :
package waf.yty.web.listener;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
public class BListener implements ServletContextAttributeListener {
public void attributeAdded(ServletContextAttributeEvent scab) {
System.out.println("您向application中添加了一个名为" + scab.getName() +
",值为" + scab.getValue() + "的属性");
}
public void attributeRemoved(ServletContextAttributeEvent scab) {
System.out.println(scab.getName() + "=" + scab.getValue());
}
public void attributeReplaced(ServletContextAttributeEvent scab) {
System.out.println(scab.getName() + "=" + scab.getValue() + ","
+ scab.getServletContext().getAttribute(scab.getName()));
}
}
web.xml :
<listener>
<listener-class>waf.yty.web.listener.BListener</listener-class>
</listener>
add.jsp :
<body>
<%
application.setAttribute("waf", "WAF");
%>
</body>
replace.jsp :
<body>
<%
application.setAttribute("waf", "ZZZ");
%>
</body>
remove.jsp :
<body>
<%
application.removeAttribute("waf");
%>
</body>
1.2、ServletRequestAttributeListener和HttpSessionAttributeListener监听器案例
CListener.java :
package waf.yty.web.listener;
import java.text.MessageFormat;
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
public class CListener implements HttpSessionAttributeListener, ServletRequestAttributeListener {
public void attributeAdded(ServletRequestAttributeEvent srae) {
String str = MessageFormat.format("ServletRequest域对象中添加了属性:{0},属性值是:{1}"
,srae.getName()
,srae.getValue());
System.out.println(str);
}
public void attributeRemoved(ServletRequestAttributeEvent srae) {
String str = MessageFormat.format("ServletRequest域对象中删除了属性:{0},属性值是:{1}"
,srae.getName()
,srae.getValue());
System.out.println(str);
}
public void attributeReplaced(ServletRequestAttributeEvent srae) {
String str = MessageFormat.format("ServletRequest域对象中替换了属性:{0},属性值是:{1}"
,srae.getName()
,srae.getValue());
System.out.println(str);
}
public void attributeAdded(HttpSessionBindingEvent se) {
String str = MessageFormat.format("HttpSession域对象中添加了属性:{0},属性值是:{1}"
,se.getName()
,se.getValue());
System.out.println(str);
}
public void attributeRemoved(HttpSessionBindingEvent se) {
String str = MessageFormat.format("HttpSession域对象中删除了属性:{0},属性值是:{1}"
,se.getName()
,se.getValue());
System.out.println(str);
}
public void attributeReplaced(HttpSessionBindingEvent se) {
String str = MessageFormat.format("HttpSession域对象中替换了属性:{0},属性值是:{1}"
,se.getName()
,se.getValue());
System.out.println(str);
}
}
web.xml :
<listener>
<listener-class>waf.yty.web.listener.CListener</listener-class>
</listener>
rsTest.jsp :
<body>
<%
session.setAttribute("aa", "bb");
session.setAttribute("aa", "cc");
session.removeAttribute("aa");
request.setAttribute("AA", "BB");
request.setAttribute("AA", "DD");
request.removeAttribute("AA");
%>
</body>
二、感知Session绑定的事件监听器
保存在Session域中的对象可以有多种状态:绑定(session.setAttribute("bean",Object))到Session中;从 Session域中解除(session.removeAttribute("bean"))绑定;随Session对象持久化到一个存储设备中;随Session对象从一个存储设备中恢复。
Servlet 规范中定义了两个特殊的监听器接口"HttpSessionBindingListener和HttpSessionActivationListener"来帮助JavaBean 对象了解自己在Session域中的这些状态: ,实现这两个接口的类不需要 web.xml 文件中进行注册。
2.1、HttpSessionBindingListener接口
实现了HttpSessionBindingListener接口的JavaBean对象可以感知自己被绑定到Session中和从Session中删除的事件。
当对象被绑定到HttpSession对象中时,web服务器调用该对象的void valueBound(HttpSessionBindingEvent event)方法
当对象从HttpSession对象中解除绑定时,web服务器调用该对象的void valueUnbound(HttpSessionBindingEvent event)方法
案例 :
User.java :
package waf.yty.web.listener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
public class User implements HttpSessionBindingListener{
private String username;
private String password;
public User(String username, String password) {
super();
this.username = username;
this.password = password;
}
public User() {
super();
// TODO Auto-generated constructor stub
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User [username=" + username + ", password=" + password + "]";
}
public void valueBound(HttpSessionBindingEvent arg0) {
System.out.println("或许这就是Session上流社会吧!");
}
public void valueUnbound(HttpSessionBindingEvent arg0) {
System.out.println("Session我去也!");
}
}
addAndRemove.jsp :
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page import="waf.yty.web.listener.User" %>
<html>
<head>
<title>My JSP 'addAndRemove.jsp' starting page</title>
</head>
<body>
<%
User user = new User();
// 添加到Session
session.setAttribute("user", user);
// 从Session中溢出
session.removeAttribute("user");
%>
</body>
</html>
2.2、HttpSessionActivationListener接口
实现了HttpSessionActivationListener接口的JavaBean对象可以感知自己被活化(反序列化)和钝化(序列化)的事件
当绑定到HttpSession对象中的javabean对象将要随HttpSession对象被钝化(序列化)之前,web服务器调用该javabean对象的void sessionWillPassivate(HttpSessionEvent event) 方法。这样javabean对象就可以知道自己将要和HttpSession对象一起被序列化(钝化)到硬盘中。
当绑定到HttpSession对象中的javabean对象将要随HttpSession对象被活化(反序列化)之后,web服务器调用该javabean对象的void sessionDidActive(HttpSessionEvent event)方法。这样javabean对象就可以知道自己将要和 HttpSession对象一起被反序列化(活化)回到内存中。
JavaBean对象一定要实现序列化 (Serializable) 接口,否则会在Session钝化到硬盘之前被杀死,再查询就为NULL !
示例:
User.java :
package waf.yty.pojo;
import java.io.Serializable;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionEvent;
/**
* 实现了HttpSessionActivationListener接口的 JavaBean 对象可以感知自己被活化和钝化的事件
活化:javabean对象和Session一起被反序列化(活化)到内存中。
钝化:javabean对象存在Session中,当服务器把session序列化到硬盘上时,如果Session中的javabean对象实现了Serializable接口
那么服务器会把session中的javabean对象一起序列化到硬盘上,javabean对象和Session一起被序列化到硬盘中的这个操作称之为钝化
如果Session中的javabean对象没有实现Serializable接口,那么服务器会先把Session中没有实现Serializable接口的javabean对象移除
然后再把Session序列化(钝化)到硬盘中
当绑定到 HttpSession对象中的javabean对象将要随 HttpSession对象被钝化之前,
web服务器调用该javabean对象对象的 void sessionWillPassivate(HttpSessionEvent event)方法
这样javabean对象就可以知道自己将要和 HttpSession对象一起被序列化(钝化)到硬盘中
当绑定到HttpSession对象中的javabean对象将要随 HttpSession对象被活化之后,
web服务器调用该javabean对象的 void sessionDidActive(HttpSessionEvent event)方法
这样javabean对象就可以知道自己将要和 HttpSession对象一起被反序列化(活化)回到内存中
* @author yangtengyu
*
*/
public class User implements HttpSessionActivationListener, Serializable {
public void sessionWillPassivate(HttpSessionEvent arg0) {
System.out.println("钝化到硬盘");
}
public void sessionDidActivate(HttpSessionEvent arg0) {
System.out.println("活化回内存");
}
}
在WebRoot\META-INF文件夹下创建一个context.xml文件 :
<Context>
<!-- 1分钟之后就将HttpSession对象钝化到本地硬盘的一个gacl文件夹中 -->
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
<Store className="org.apache.catalina.session.FileStore" directory="de_cache"/>
</Manager>
</Context>
a.jsp :
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page import="waf.yty.pojo.User" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'a.jsp' starting page</title>
</head>
<body>
<h1>向session中保存session数据</h1>
<%
User user = new User();
session.setAttribute("user", user);
%>
</body>
</html>
b.jsp :
</head>
<body>
<h1>获取session中的数据</h1>
<%
out.print(session.getAttribute("user"));
%>
</body>
</html>
访问这个a.jsp页面,服务器就会马上创建一个HttpSession对象,然后将实现了HttpSessionActivationListener接口的JavaBean对象绑定到session对象中,这个jsp页面在等待1分钟之后没有人再次访问,那么服务器就会自动将这个HttpSession对象钝化(序列化)到硬盘上。
我们可以在tomcat服务器的work\Catalina\localhost\JavaWeb_Listener_20140908\gacl文件夹下找到序列化到本地存储的session,它会生成一个context.xml中directory的value值的文件夹,里面生成一个以.session结尾的文件。