JSP Listener (监听器)小结

一、什么是监听器

监听器是Servlet规范中定义的一种特殊类,用于监听ServletContextHttpSessionServletRequest等域对象的创建和销毁事件,它还可以监听域对象的属性发生修改的事件,可以在事件发生前或者发生后做一些必要的处理。

在Servlet中要创建监听器类首先需要新建一个类并继承相应的监听器接口,实现接口中定义的方法,然后在web.xml文件中注册相应的监听器即可。如果一个web.xml文件中注册了多个监听器,则监听器的启动顺序按照在web.xml中的注册顺序启动。如果一个web.xml文件中同时定义了监听器、过滤器和Servlet,那么web容器会先加载监听器、再加载过滤器最后加载Servlet。

二、监听器的分类

按照监听的事件可以将监听器划分为以下三类:

1、监听域对象自身的创建和销毁的事件监听器;

2、监听域对象中属性的增加和删除的事件监听器;

3、监听绑定到HttpSession域中某个对象状态的事件监听器。

三、常用监听器接口

在这里插入图片描述

1、监听域对象自身的创建和销毁的事件监听器

这一类监听器主要监听ServletContextHttpSessionServletRequest这三个域对象创建和销毁的事件,要实现这一类监听器,需要继承ServletContextListenerHttpSessionListener或者ServletRequestListener接口,分别来对这三个域对象进行分析。

(1)首先是继承ServletContextListener,这一类监听器主要监听应用程序环境发生的事件,而要继承ServletContextListener,就需要实现该接口中的contextInitializedcontextDestroyed方法,简单地说就是启动服务器创建应用程序上下文时和关闭服务器销毁程序上下文时执行的操作。可以参考下面的实例:

package com.imooc.listener;
 
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
 
/**
 * Application Lifecycle Listener implementation class MyServletContextListener
 *
 */
public class MyServletContextListener implements ServletContextListener {
 
    /**
     * Default constructor. 
     */
    public MyServletContextListener() {
    }
 
	/**
     * @see ServletContextListener#contextDestroyed(ServletContextEvent)
     */
    public void contextDestroyed(ServletContextEvent arg0)  { 
        System.out.println("contextDestroyed");
    }
 
	/**
     * @see ServletContextListener#contextInitialized(ServletContextEvent)
     */
    public void contextInitialized(ServletContextEvent arg0)  { 
    	String name = arg0.getServletContext().getInitParameter("name");
    	System.out.println("contextInitialized : name=" + name);
    }
	
}

这个例子中在服务器启动时,运行contextInitialized方法,可以通过ServletContextEvent来获取服务器启动的初始参数,这些初始参数都是在web.xml文件中配置的。当服务器停止时,会执行监听器的contextDestroyed方法,进行资源的回收等操作。定义了监听器之后,就可以在web.xml中注册监听器了,注册内容如下,同时还定义了初始化参数。

  <listener>
    <listener-class>com.imooc.listener.MyServletContextListener</listener-class>
  </listener>
  <context-param>
  	<param-name>name</param-name>
  	<param-value>imooc</param-value>
  </context-param>

这时启动服务器,观察启动日志,会发现打印出如下的日志,获取到了初始化参数name的值并打印出来,说明监听器已经启动了。

……
八月 23, 2016 8:38:19 下午 org.apache.jasper.servlet.TldScanner scanJars
信息: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
contextInitialized : name=imooc
八月 23, 2016 8:38:19 下午 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["http-nio-8080"]
……

再停止服务器,会发现打印了执行监听器里destroy方法的内容。

……
八月 23, 2016 8:40:58 下午 org.apache.catalina.core.StandardService stopInternal
信息: Stopping service Catalina
contextDestroyed
八月 23, 2016 8:40:58 下午 org.apache.coyote.AbstractProtocol stop
信息: Stopping ProtocolHandler ["http-nio-8080"]
……

(2)接下来看继承HttpSessionListener的监听器,这一类监听器监听的是用户会话对象的创建和销毁事件,定义如下的监听器,在创建和销毁会话对象时将输出一句话。

package com.imooc.listener;
 
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
 
/**
 * Application Lifecycle Listener implementation class MySessionListener
 *
 */
public class MySessionListener implements HttpSessionListener {
 
    /**
     * Default constructor. 
     */
    public MySessionListener() {
    }
 
	/**
     * @see HttpSessionListener#sessionCreated(HttpSessionEvent)
     */
    public void sessionCreated(HttpSessionEvent arg0)  { 
         System.out.println("sessionCreated");
    }
 
	/**
     * @see HttpSessionListener#sessionDestroyed(HttpSessionEvent)
     */
    public void sessionDestroyed(HttpSessionEvent arg0)  { 
    	System.out.println("sessionDestroyed");    
    }
	
}

接着需要在web.xml中注册相应的监听器。

  <listener>
    <listener-class>com.imooc.listener.MySessionListener</listener-class>
  </listener>

启动项目,打开浏览器访问初始页面index.jsp,会发现控制台打印sessionCreated,关闭用户会话,这时会打印sessionDestroyed。

(3)最后看一下继承ServletRequestListener接口的监听器,这一类监听器监听的是用户请求对象,当请求被创建和销毁时会执行监听器中的方法。例如定义如下的监听器来监听请求对象的创建和销毁动作,当请求被创建时会通过ServletRequestEvent对象获取请求参数name的值。

package com.imooc.listener;
 
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
 
/**
 * Application Lifecycle Listener implementation class MyRequestListener
 *
 */
public class MyRequestListener implements ServletRequestListener {
 
    /**
     * Default constructor. 
     */
    public MyRequestListener() {
    }
 
	/**
     * @see ServletRequestListener#requestDestroyed(ServletRequestEvent)
     */
    public void requestDestroyed(ServletRequestEvent arg0)  { 
    	System.out.println("requestDestroyed");
    }
 
	/**
     * @see ServletRequestListener#requestInitialized(ServletRequestEvent)
     */
    public void requestInitialized(ServletRequestEvent arg0)  { 
    	System.out.println("requestDestroyed : name=" + arg0.getServletRequest().getParameter("name"));
    }
}

启动项目,访问index.jsp?name=imooc,这里定义一个名为name的参数,参数值是imooc,提交请求,这时后台会打印

requestDestroyed : name=imooc
requestDestroyed

首先用户提交请求时,请求对象被创建,监听器监听到请求对象创建的事件,这时执行监听器的initialize方法,同时监听器获取到参数名为name的参数值并打印。因为request对象只在一次请求有效,所以服务器返回响应后请求对象便被销毁,这时执行监听器的destory方法。

2、监听域对象中属性的增加和删除的事件监听器

这一类监听器主要监听ServletContext、HttpSession和ServletRequest这三个域对象中属性的创建、销毁和修改的事件,要实现这三种监听器,就需要继承ServletContextAttributeListenerHttpSessionAttributeListenerServletRequestAttributeListener这三个接口,并实现接口中的方法,下面通过一个实例来分析这三种类型的监听器。首先分别定义三个监听器分别表示这三种类型的监听器,定义如下,这三个监听器都是监听域对象中属性的创建、修改和删除动作并打印出相应的属性名称。

package com.imooc.listener;
 
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
 
/**
 * Application Lifecycle Listener implementation class MyServletContextAttributeListener
 *
 */
public class MyServletContextAttributeListener implements ServletContextAttributeListener {
 
    /**
     * Default constructor. 
     */
    public MyServletContextAttributeListener() {
    }
 
	/**
     * @see ServletContextAttributeListener#attributeAdded(ServletContextAttributeEvent)
     */
    public void attributeAdded(ServletContextAttributeEvent arg0)  { 
        System.out.println("ServletContext_attributeAdded : name=" + arg0.getName());
    }
 
	/**
     * @see ServletContextAttributeListener#attributeRemoved(ServletContextAttributeEvent)
     */
    public void attributeRemoved(ServletContextAttributeEvent arg0)  { 
    	System.out.println("ServletContext_attributeRemoved : name=" + arg0.getName());
    }
 
	/**
     * @see ServletContextAttributeListener#attributeReplaced(ServletContextAttributeEvent)
     */
    public void attributeReplaced(ServletContextAttributeEvent arg0)  { 
    	System.out.println("ServletContext_attributeReplaced : name=" + arg0.getName());
    }
	
}
package com.imooc.listener;
 
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
 
/**
 * Application Lifecycle Listener implementation class MySessionAttributeListener
 *
 */
public class MySessionAttributeListener implements HttpSessionAttributeListener {
 
    /**
     * Default constructor. 
     */
    public MySessionAttributeListener() {
    }
 
	/**
     * @see HttpSessionAttributeListener#attributeAdded(HttpSessionBindingEvent)
     */
    public void attributeAdded(HttpSessionBindingEvent arg0)  { 
    	System.out.println("Session_attributeAdded : name=" + arg0.getName());
    }
 
	/**
     * @see HttpSessionAttributeListener#attributeRemoved(HttpSessionBindingEvent)
     */
    public void attributeRemoved(HttpSessionBindingEvent arg0)  { 
    	System.out.println("Session_attributeRemoved : name=" + arg0.getName());
    }
 
	/**
     * @see HttpSessionAttributeListener#attributeReplaced(HttpSessionBindingEvent)
     */
    public void attributeReplaced(HttpSessionBindingEvent arg0)  { 
    	System.out.println("Session_attributeReplaced : name=" + arg0.getName());
    }
	
}
package com.imooc.listener;
 
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
 
/**
 * Application Lifecycle Listener implementation class MyRequestAttributeListener
 *
 */
public class MyRequestAttributeListener implements ServletRequestAttributeListener {
 
    /**
     * Default constructor. 
     */
    public MyRequestAttributeListener() {
    }
 
	/**
     * @see ServletRequestAttributeListener#attributeRemoved(ServletRequestAttributeEvent)
     */
    public void attributeRemoved(ServletRequestAttributeEvent arg0)  { 
    	System.out.println("Request_attributeRemoved : name=" + arg0.getName());
    }
 
	/**
     * @see ServletRequestAttributeListener#attributeAdded(ServletRequestAttributeEvent)
     */
    public void attributeAdded(ServletRequestAttributeEvent arg0)  { 
    	System.out.println("Request_attributeAdded : name=" + arg0.getName());
    }
 
	/**
     * @see ServletRequestAttributeListener#attributeReplaced(ServletRequestAttributeEvent)
     */
    public void attributeReplaced(ServletRequestAttributeEvent arg0)  { 
    	System.out.println("Request_attributeReplaced : name=" + arg0.getName());
    }
	
}

定义好三个监听器之后就可以在web.xml中进行注册了。

  <listener>
    <listener-class>com.imooc.listener.MyServletContextAttributeListener</listener-class>
  </listener>
  <listener>
    <listener-class>com.imooc.listener.MySessionAttributeListener</listener-class>
  </listener>
  <listener>
    <listener-class>com.imooc.listener.MyRequestAttributeListener</listener-class>
  </listener>

这时可以写几个页面来做一下测试,首先写一个index.jsp,页面里只包括两个超链接,链接到连个页面分别做添加属性和删除属性操作。

<a href="addAttribute.jsp">Add attribute</a><br/>
<a href="removeAttribute.jsp">Remove attribute</a>

addAttribute.jsp页面如下,这个页面里可以给三个域对象分别新增一个属性。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Insert title here</title>
</head>
<body>
	Add attribute
	<a href="addAttribute.jsp">Add attribute</a>
	<a href="removeAttribute.jsp">Remove attribute</a>
	<%
		request.setAttribute("attributeName", "attributeValue");
		request.getSession().setAttribute("attributeName", "attributeValue");
		request.getServletContext().setAttribute("attributeName", "attributeValue");
	%>
</body>
</html>

removeAttribute.jsp页面如下,页面将三个域对象中的属性移除。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Insert title here</title>
</head>
<body>
	Remove attribute
	<a href="addAttribute.jsp">Add attribute</a>
	<a href="removeAttribute.jsp">Remove attribute</a>
	<%
		request.removeAttribute("attributeName");
		request.getSession().removeAttribute("attributeName");
		request.getServletContext().removeAttribute("attributeName");
	%>
</body>
</html>

这时再点击removeAttribute.jsp,后台打印如下,可以发现request域对象的属性没有被移除,这里的原理和上面域对象属性的修改是一样的。

Session_attributeRemoved : name=attributeName
ServletContext_attributeRemoved : name=attributeName

要想能够执行Request域对象监听器里属性的修改和删除方法,可以在addAttribute.jsp里稍作修改,在程序最后重新给属性赋值,然后删除属性,在运行程序,就可以了,具体代码如下。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Insert title here</title>
</head>
<body>
	Add attribute
	<a href="addAttribute.jsp">Add attribute</a>
	<a href="removeAttribute.jsp">Remove attribute</a>
	<%
		request.setAttribute("attributeName", "attributeValue");
		request.getSession().setAttribute("attributeName", "attributeValue");
		request.getServletContext().setAttribute("attributeName", "attributeValue");
		request.setAttribute("attributeName", "attributeValue");
		request.removeAttribute("attributeName");
	%>
</body>
</html>

运行程序,访问addAttribute.jsp,这时控制台打印如下信息,说明监听器的修改和删除属性的方法也被执行到了。

Request_attributeAdded : name=attributeName
Session_attributeAdded : name=attributeName
ServletContext_attributeAdded : name=attributeName
Request_attributeReplaced : name=attributeName
Request_attributeRemoved : name=attributeName

3、监听绑定到HttpSession域中某个对象状态的事件监听器

下面来看最后一类监听器,这类监听器主要监听的是绑定到HttpSession域中某个对象状态的事件,HttpSession中对象的状态有两种:绑定与解除绑定、钝化与活化。所谓的绑定与解除绑定,就是指在HttpSession中将某个对象设置为属性值或者移除某个属性的值。而钝化是指服务器会将不常使用的Session对象暂时序列化到系统文件或数据库中,而活化就是将暂存在系统文件或数据库中的Session对象反序列化到服务器中,当Tomcat服务器被关闭或者重启时,Tomcat会将Session对象钝化到服务器文件系统中,当服务器被重新加载时,Session对象也会被钝化。要实现这两种的监听器,就需要继承HttpSessionBindingListenerHttpSessionActivationListener,下面分别来分析。

(1)先来看继承HttpSessionBindingListener接口的监听器,要注意这一类监听器在被定义之后不需要在web.xml文件中进行注册,这一类的监听器可以定义成一个JavaBean的形式,可以在里面设置属性等,同时要注意的是这一类的监听器也要实现Serializable接口,例如定义一个User类如下,实现了valueBound方法用于监听绑定动作、valueUnbound方法用于监听解除绑定动作

package com.imooc.listener;
 
import java.io.Serializable;
 
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import javax.servlet.http.HttpSessionEvent;
 
/**
 * Application Lifecycle Listener implementation class User
 *
 */
public class User implements HttpSessionBindingListener, Serializable{
 
    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;
 
	/**
     * Default constructor. 
     */
    public User() {
    }
 
	/**
     * @see HttpSessionBindingListener#valueBound(HttpSessionBindingEvent)
     */
    public void valueBound(HttpSessionBindingEvent paramHttpSessionBindingEvent)  { 
    	System.out.println("valueBound : name=" + paramHttpSessionBindingEvent.getName());
    }
 
	/**
     * @see HttpSessionBindingListener#valueUnbound(HttpSessionBindingEvent)
     */
    public void valueUnbound(HttpSessionBindingEvent paramHttpSessionBindingEvent)  { 
    	System.out.println("valueUnbound : name=" + paramHttpSessionBindingEvent.getName());
    }
}

现在就可以使用上面的addAttribute.jsp和removeAttribute.jsp来验证一下了,修改两个页面的代码。

<%@page import="com.imooc.listener.User"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Insert title here</title>
</head>
<body>
	Add attribute
	<a href="addAttribute.jsp">Add attribute</a>
	<a href="removeAttribute.jsp">Remove attribute</a>
	<%
		request.setAttribute("attributeName", "attributeValue");
		request.getSession().setAttribute("attributeName", "attributeValue");
		request.getServletContext().setAttribute("attributeName", "attributeValue");
		request.setAttribute("attributeName", "attributeValue");
		request.removeAttribute("attributeName");
		request.getSession().setAttribute("currentUser", new User());
	%>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Insert title here</title>
</head>
<body>
	Remove attribute
	<a href="addAttribute.jsp">Add attribute</a>
	<a href="removeAttribute.jsp">Remove attribute</a>
	<%
		request.removeAttribute("attributeName");
		request.getSession().removeAttribute("attributeName");
		request.getServletContext().removeAttribute("attributeName");
		request.getSession().removeAttribute("currentUser");
	%>
</body>
</html>

我们会发现这里绑定对象与解除绑定使用的仍然是Session的setAttributeremoveAttribute方法,这和前面设置属性是一样的,那么这种绑定对象的监听器与设置属性的监听器有什么区别呢?绑定对象的监听器只监听某种类型的对象的绑定与解绑操作,而设置属性的监听器监听的是所有设置属性的动作。运行程序,点击addAttribute.jsp,这时后台打印valueBound : name=currentUser,再点击removeAttribute,这时后台打印valueUnbound : name=currentUser,说明监听器监听成功。

(2)最后来看一下继承HttpSessionActivationListener的监听器,这一类监听器不常用,了解一下即可。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值