Servlet监听器Listener
用于监听ServletContext、HttpSession和ServletRequest等域对象的创建与销毁事件,以及监听这些域对象中属性发生修改的事件。
监听对象:
1、ServletContext:application,整个应用只存在一个
2、HttpSession:session,针对每一个对话
3、ServletRequest:request,针对每一个客户请求
监听内容:创建、销毁、属性改变事件
监听作用:可以在事件发生前、发生后进行一些处理,一般可以用来统计在线人数和在线用户、统计网站访问量、系统启动时初始化信息等。
创建步骤:
1、创建一个实现监听器接口的类
2、配置web.xml文件,注册监听器
<listener>
<listener-class>完整类名</listener-class>
</listener>
监听器的启动顺序:按照web.xml的配置顺序来启动
加载顺序:监听器>过滤器>Servlet
- a 按照监听的对象划分
用于监听应用程序环境对象(ServletContext)的事件监听器,实现ServletContextListener、ServletContextAttributeListener接口
用于监听用户会话对象(HttpSeesion)的事件监听器,实现HttpSessionListener、HttpSessionAttributeListener接口
用于监听请求消息对象(ServletRequest)的事件监听器,实现ServletRequestListener、ServletRequestAttributeListener接口
b 按照监听事件划分
1、监听域对象自身的创建和销毁的事件监听器
根据监听对象不同分别实现ServletContextListener、HttpSessionListener、ServletRequestListener接口。
①ServletContext的创建和销毁:contextInitialized方法和contextDestroyed方法
public void contextInitialized(ServletContextEvent sce)//ServletContext创建时调用
public void contextDestroyed(ServletContextEvent sce)//ServletContext销毁时调用
主要用途:作为定时器、加载全局属性对象、创建全局数据库连接、加载缓存信息等
实例:
在web.xml中可以配置项目初始化信息,在contextInitialized方法中进行启动
<context-param>
<param-name>属性名</param-name>
<param-value>属性值</param-value>
</context-param>
自定义监听器
public class MyFirstListener implements ServletContextListener{
public void contextInitialized(ServletContextEvent sce){
//获取web.xml中配置的属性
String value=sce.getServletContext().getInitParameter("属性名");
System.out.println(value);
}
public void contextDestroyed(ServletContextEvent sce){
//关闭时操作
}
}
②HttpSession的创建和销毁:sessionCreated和sessionDestroyed方法
public void sessionCreated(HttpSessionEvent se)//session创建时调用
public void sessionDestroyed(HttpSessionEvent se)//session销毁时调用
主要用途:统计在线人数、记录访问日志等
【注】
web.xml配置session超时参数,单位:分,session超时的时间并不是精确的
<session-config>
<session-timeout>10</session-timeout>
</session-config>
③ServletRequest的创建和销毁:requestInitialized和requestDestroyed方法
public void requestInitialized(ServletRequestEvent sre)//request创建时调用
public void requestDestroyed(ServletRequestEvent sre)//request销毁时调用
主要用途:读取request参数,记录访问历史
实例:
public class MySRequestListener implements SevletRequestListener{
public void requestInitialized(ServletRequestEvent sre){
String value=sre.getServletRequest().getParameter("key");//获取request中的参数
System.out.println(value);
}
public void requestDestroyed(ServletRequestEvent sre){
System.out.println("request destroyed");
}
}
2、监听域对象中的属性的增加和删除的事件监听器
根据监听对象不同分别实现ServletContextAttributeListener、HttpSessionAttributeListener、ServletRequestAttributeListener接口。
实现方法:attributeAdded、attributeRemoved、attributeReplaced
3、监听绑定到HttpSeesion域中的某个对象的状态的事件监听器(创建普通JavaBean)
HttpSession中的对象状态:绑定→解除绑定;钝化→活化
实现接口及方法:HttpSessionBindingListener接口(valueBound和valueUnbound方法)、HttpSessionActivationListener接口(sessionWillPassivate和sessionDidActivate方法)
【注1】①要实现钝化和活化必须实现Serializable接口
②不需要在web.xml中注册
【注2】
绑定: 通过setAttribute保存到session对象当中
解除绑定: 通过removeAttribue去除
钝化: 将session对象持久化到存储设备上
活化: 将session对象从存储设备上进行恢复
session钝化机制:
①把服务器不常使用的session对象暂时序列化到系统文件或者是数据库中,当使用时反序列化到内存中,整个过程由服务器自动完成;
②session的钝化机制由SessionManager管理,创建一个普通的JavaBean绑定和接触需要实现HttpSessionBindingListener接口
使用注解
@WebListener的常用属性
属性名 | 类型 | 是否可选 | 描述 |
---|---|---|---|
value | String | 是 | 该监听器的描述信息 |
@WebListener(“This is a listener”)
public class FirstListener impliements ServletRequestListener{}
该注解用于将类声明为监听器,被 @WebListener 标注的类必须实现以下至少一个接口:
ServletContextListener
ServletContextAttributeListener
ServletRequestListener
ServletRequestAttributeListener
HttpSessionListener
HttpSessionAttributeListener
HttpSessionBindingListener和HttpSessionAttributeListener
1.BindingListener有2个方法,valueBound(HttpSessinBindingEvent)和valueUnbount(HttpSessionBindingEvent)。实现BindingListener接口的对象被绑 定到session时触发valueBound事件,解除绑定时触发valueUnbound事件。举例来说:
public class UserObject implements HttpSessionBindingListener{
public void valueBound(HttpSessionBindingEvent event){
System.out.println("触发绑定事件!");
}
public void valueUnbound(HttpSessionBindingEvent event){
System.out.println("解除和session的绑定");
}
UserObject user = new UserObject();
当把该监听器保存到session中,session.setAttribute(“user”,user)时就会触发valueBound事件.
当该监听器从session中移除时即session.removeAttribute(“user”),触发valueUnbound事件;session失效或超时
时也会触发valueUnbound事件。
注意:只有当该监听器(UserObject)保存到session中或从session移除时才会触发事件,其他没有实现该listener对象保存到session时不会触发该事件。
2.AttributeListener接口有3方法,attributeAdded(HttpSessionBindingEvent),attributeRemoved(HttpSessionBindingEvent),
attributeReplaced(HttpSeesionEvent)。当在session中添加、移除或更改属性值时会触发相应的事件。
MyListener implements HttpSessionAttributeListener{
attributeAdded(HttpSessionBindingEvenet event){
System.out.println("有对象加入session中");
}
attributeRemoved(HttpSessionBindingEvent event){
System.out.println("有对象从session中移除");
}
attributeReplaced(HttpSessionBindingEvent event){
System.out.println("属性值改变");
}
}
OtherObject other = new OtherObject();
当有对象添加到session中时,session.setAttribute(“object”,other)触发attributeAdded事件,
当该对象从session移除时,session.removeAttribute(“object”)触发attriubteRemoved事件,
当该属性的值发生变化时, session.replaceAttribute(“object”,another)触发attributeRepalced事件。
注意:只要有对象保存到session中或从session中移除或改变属性的值都会触发相应事件,不论该对象是否实现了AttributeListener。
总结:
1.只有实现了HttpSessionBindingListener的类,在和session绑定、解除绑定时触发其事件。
2.实现了HttpSessionAttributeListener后,任何对象(不论其是否实现了AttributeListener)在变化时均触发对应的事件。
HttpSessionActivationListener监听session对象的序列化与反序列化
HttpSessionActivationListener用于监控实现类本身,当实现类对象被添加到session中(session.setAttribute())后,session对象序列化(钝化)前和反序列化(活化)后都会被执行,相应的方法。
• sessionWillPassivate(HttpSessionEvent se) session钝化前执行(session从内存到硬盘)
• sessionDidActivate(HttpSessionEvent se) session活化后执行(session从硬盘到内存)
2.我们通过在META-INF目录下配置context.xml文件,设置失效时间和session序列化的保存路径,配置如下:
<Context>
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
<Store className="org.apache.catalina.session.FileStore" directory="d:/session"/>
</Manager>
</Context>
• maxIdlSwap="1"表示失效时间为1分钟
• directory="d:/session"是session保存路径
然后定义一个类实现HttpSessionActivationListener接口,监听session的序列化
public class ListenerTest implements HttpSessionActivationListener,Serializable {
private static final long serialVersionUID = -8367567842003252055L;
private String name ;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public ListenerTest(String name) {
this.name = name;
}
//对象实例化后保存到session中,当session失效要被序列化前执行,(只有保存到session中的对象才会被监听到)
public void sessionWillPassivate(HttpSessionEvent se) {
System.out.println(name + "=>序列化到(钝化)到硬盘中,JSessionId是:"+se.getSession().getId());
}
//当session被反序列化后执行
public void sessionDidActivate(HttpSessionEvent se) {
System.out.println(name + "=>反序列化到(活化)到内存中,JSessionId是:"+se.getSession().getId());
}
jsp页面
<%
session.setAttribute("sessionBean",new ListenerTest("AAAA"));
%>
需要注意的是存在该session时候在序列化有可能导致失败 稍等一会就好了
User 实体类
public class User {
//当前用户的session id
private String sessionId;
//当前用户的ip地址
private String ip;
//当前用户第一次访问的时间
private String firstTime;
public User() {
super();
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getFirstTime() {
return firstTime;
}
public void setFirstTime(String firstTime) {
this.firstTime = firstTime;
}
public String getSessionId() {
return sessionId;
}
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
}
HttpSessionListener监听器
@WebListener
public class MyHttpSessionListener implements HttpSessionListener{
//当前用户数
private int userCounts=0;
@Override
public void sessionCreated(HttpSessionEvent se) {
//sessionCreated 用户数+1
userCounts++;
//重新在servletContext中保存userCounts
se.getSession().getServletContext().setAttribute("userCounts", userCounts);
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
//sessionDestroyed 用户数-1
userCounts--;
//重新在servletContext中保存userCounts
se.getSession().getServletContext().setAttribute("userCounts", userCounts);
@SuppressWarnings("unchecked")
ArrayList<User> userList=(ArrayList<User>) se.getSession().getServletContext().getAttribute("userList");
String sessionId=se.getSession().getId();
//如果当前用户在userList中 在session销毁时 将当前用户移出userList
if(SessionUtil.getUserBySessionId(userList, sessionId)!=null){
userList.remove(SessionUtil.getUserBySessionId(userList, sessionId));
}
//将userList集合 重新保存到servletContext
se.getSession().getServletContext().setAttribute("userList", userList);
}
}
ServletRequestListener监听器
@WebListener
public class MyServletRequestListener implements ServletRequestListener {
//用户集合
private ArrayList<User> userList;
@Override
public void requestDestroyed(ServletRequestEvent arg0) {
}
@SuppressWarnings("unchecked")
@Override
public void requestInitialized(ServletRequestEvent arg0) {
//从servletContext中获的userList
userList=(ArrayList<User>) arg0.getServletContext().getAttribute("userList");
//如果servletContext中没有userList对象 初始化userList
if(userList==null){
userList=new ArrayList<User>();
}
HttpServletRequest request=(HttpServletRequest) arg0.getServletRequest();
//sessionId
String sessionId=request.getSession().getId();
//如果当前sessionId不存在集合中 创建当前user对象
if(SessionUtil.getUserBySessionId(userList,sessionId)==null){
User user=new User();
user.setSessionId(sessionId);
user.setIp(request.getRemoteAddr());
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd hh:MM:ss");
user.setFirstTime(sdf.format(new Date()));
userList.add(user);
}
//将userList集合 保存到ServletContext
arg0.getServletContext().setAttribute("userList", userList);
}
}
工具类
public class SessionUtil {
//根据sessionId判断当前用户是否存在在集合中 如果存在 返回当前用户 否则返回null
public static User getUserBySessionId(ArrayList<User> userList,String sessionId) {
for (User user : userList) {
if(sessionId.equals(user.getSessionId())){
return user;
}
}
return null;
}
}