第八章_监听器

8.1、监听器接口和注册

创建监听器的监听器接口属于javax.servletjavax.servlet.http包的一部分,详情如下:

javax.servlet.ServletContextListener。这是对Servlet Context生命周期事件做出响应的监听器。创建好Servlet Context时会马上调用它的一个方法,并在关闭Servlet Context之前调用它的另一个方法。

javax.servlet.ServletContextAttributeListener。这是在添加、删除或替换某个Servlet Context属性时采取相应动作的监听器。

javax.servlet.http.HttpSessionAttributeListener。这是在创建、移除或替换Servlet上下文属性时响应的监听器。

javax.servlet.http.HttpSessionAttributeListener。这是在添加、删除或替换某个session属性时被调用的监听器。

javax.servlet.httpSessionActivationListener。这是在打开和关闭某个HttpSession时被调用的监听器。

javax.servlet.http.HttpSessionBindingListener。这是一个类,其实例将被保存为可以实现这个接口的HttpSession属性。当它在HttpSession中被添加或者删除时,实现HttpSessionBindingListener的类实例会收到通知。

javax.servlet.ServletRequestListener。这是对ServletRequest的创建和删除做出响应的监听器。

javax.servlet.ServletRequestAttributeListener。当ServletRequest中添加、删除或替换掉某个属性时,会调用该监听器的方法。

javax.servlet.AsyncListener。用于异步操作的监听器。

创建监听器时,只要创建一个实现相关接口的java类即可。在Servlet 3.0中。注册监听器有两种方法。

1、注解

@WebListener

public class ListenerClass implements ListenerInterface{

}

2、配置文件

<listener>

<listener-class>fully-qualified listener class</listener-class>

</listener>

在应用程序中可以想要多少个监听器就可以有多少个监听器。注意,对监听器方法的调用是同步进行的。

 

8.2ServletContext监听器

ServletContext级别上有两个监听器接口:ServletContextListenerServletContextAttributeListener

 

8.2.1ServletContextListener

ServletContextListener会对ServletContext的初始化和解构做出响应。ServletContext被初始化时,Servlet容器会在所有已注册的ServletContextListener中调用contextInitialized方法,其方法签名如下:

void contextInitialized(ServletContextEvent event)

ServletContext要被解构和销毁时,Servlet容器会在所有已注册的ServletContextListener中调用contextDestroyed方法,以下是contextDestroyed的方法签名:

void contextDestroyed(ServletContextEvent event)

contentInitializedcontextDestroyed都会收到一个来自Servlet容器的ServletContextEventjava.util.EventObject类的一个派生类:javax.servlet.ServletContextEvent。定义了一个返回ServletContextgetServletContext方法:

ServletContext getServletContext()

这个方法很重要,因为这是方位ServletContext的唯一简便方法。它有许多ServletContextListener,可以将属性保存在ServletContext中。

下面是个例子:

countries.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
  <head>
    <title>My JSP 'countries.jsp' starting page</title>
  </head>
  
  <body>
  	We operate in these countries:
  	<ul>
  		<c:forEach items="${countries}" var="country">
  			<li>${country.value}</li>
  		</c:forEach>
  	</ul>
  </body>
</html>

AppListener.java

package app08a.listener;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class AppListener implements ServletContextListener{

	@Override
	public void contextDestroyed(ServletContextEvent sce) {
	}

	@Override
	public void contextInitialized(ServletContextEvent sce) {
		System.out.println("ServletContextListener started");
		ServletContext servletContext = sce.getServletContext() ;
		Map<String,String> countries = new HashMap<String,String>() ;
		countries.put("ca", "Canada") ;
		countries.put("us", "United States") ;
		servletContext.setAttribute("countries", countries) ;
	}

}





8.2.2ServletContextAttributeListener

每当ServletContext中添加、删除或替换了某个属性时,ServletContextAttributeListener的实现都会收到通知。下面就是监听器中定义的三个方法。

void attributeAdded(ServletContextAttributeEvent event)

void attributeRemoved(ServletContextAttributeEvent event)

void attributeReplaced(ServletContextAttributeEvent event)

每当ServletContext中添加了某个属性时,Servlet容器就会调用attributeAdded方法。每当ServletContext中删除了某个属性时,则是调用attributeRemoved方法。每当ServletContext被新的替代时,则是调用attributeReplaced方法。

ServletContextAttributeEvent类派生于ServletContextAttribute,并添加了下面这两个方法,分别用来获取属性名称和属性值。

java.lang.String getName()

java.lang.Object.getValue()

 

8.3Session监听器

HttpSession有关的监听器接口有4个:HttpSessionListenerHttpSessionActivationListenerHttpSessionAttributeListenerHttpSessionBindingListener

 

8.3.1HttpSessionListener

当有HttpSession被创建或者销毁时,Servlet容器就会调用所有已注册的HttpSessionListenerHttpSessionListener中定义的两个方法是sessionCreatedsessionDestroyed

void sessionCreated(HttpSessionEvent event)

void sessionDestroyed(HttpSessionEvent event)

这两个方法都收到一个HttpSessionEvent实例,它是java.util.Event的派生类。我们可以在HttpSessionEvent中调用getSession方法以获得所创建或销毁的HttpSessiongetSession方法签名如下:

HttpSession getSession()

下面是一个计数器的例子:

SessionListener.java

package app08a.listener;

import java.util.concurrent.atomic.AtomicInteger;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class SessionListener implements HttpSessionListener,ServletContextListener{

	@Override
	public void contextDestroyed(ServletContextEvent sce) {
	}

	@Override
	public void contextInitialized(ServletContextEvent sce) {
		ServletContext servletContext = sce.getServletContext() ;
		servletContext.setAttribute("userController", new AtomicInteger());
	}

	@Override
	public void sessionCreated(HttpSessionEvent se) {
		HttpSession session = se.getSession() ;
		ServletContext servletContext = session.getServletContext() ;
		AtomicInteger userCounter = (AtomicInteger)servletContext.getAttribute("userController") ;
		int userCount = userCounter.incrementAndGet() ;
		System.out.println("userCount increment to :" + userCount);
	}

	@Override
	public void sessionDestroyed(HttpSessionEvent se) {
		HttpSession session = se.getSession() ;
		ServletContext servletContext = session.getServletContext() ;
		AtomicInteger userCounter = (AtomicInteger)servletContext.getAttribute("userController") ;
		int userCount = userCounter.decrementAndGet() ;
		System.out.println("userCount decrement to :" + userCount);
	}

}
countries.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
  <head>
    <title>My JSP 'countries.jsp' starting page</title>
  </head>
  
  <body>
  	We operate in these countries:
  	<ul>
  		<c:forEach items="${countries}" var="country">
  			<li>${country.value}</li>
  		</c:forEach>
  	</ul>
  </body>
</html>

对刚才的jsp进行测试,控制台输出如下:

userCount increment to :1

如果你换个浏览器运行,或者等到session过期,你会发现控制台输出如下:

userCount increment to :1
userCount increment to :2


8.3.2HttpSessionAttributeListener

下面是方法:

void attributeAdded(HttpSessionBindingEvent event)

void attributeRemoved(HttpSessionBindingEvent event)

void attributeReplaced(HttpSessionBindingEvent event)

所有的监听器方法都会收到一个HttpSessionBindingEvent实例,你可以从中获得相应的HttpSession和属性值及名称。

java.lang.String getName()

java.lang.Object getValue()

 

8.3.3HttpSessionActivationListener

在分布式环境中,多个Servlet容器会配置成可伸缩的,为了节省内存,Servlet容器可以对session属性进行迁移或者序列化。一般来说,当内存比较低时,相对较少访问的对象可以序列化到备用存储设备中,这样,Servlet容器就能够注意到哪些session属性的类实现了HttpSessionActivationListener接口。

这个接口中定义了两个方法:sessionDisActivatesessionWillPassivate

void sessionDisActivate(HttpSessionEvent event)

void sessionWillPassivate(HttpSessionEvent event)

 

8.3.4HttpSessionBindingListener

HttpSessionBindingListener绑定到HttpSession,或者取消绑定时,都会收到通知。如果一个类想要知道什么时候绑定或取消绑定到HttpSession上,那么这个类要实现HttpSessionBindingListener接口,然后将它的实例保存为session属性。例如,有个对象的类实现了这个接口,当它保存为HttpSession属性时,它就可以自动更新。再比如,一但HttpSessionBindingListenerHttpSession取消绑定,它的实现就可以释放占用的资源。

package app08a.model;

import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;

public class Product implements HttpSessionBindingListener{
	private String id ;
	private String name ;
	private double price ;

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	@Override
	public void valueBound(HttpSessionBindingEvent event) {
		String attributeName = event.getName() ;
		System.out.println(attributeName + " valueBound");
	}

	@Override
	public void valueUnbound(HttpSessionBindingEvent event) {
		String attributeName = event.getName() ;
		System.out.println(attributeName + " valueUnbound");
	}

}


当监听器与HttpSession绑定或者取消绑定时,它索要做的只是将内容输出到控制台即可。

8.4ServletRequest监听器

ServletRequest级别上有3个监听器接口:ServletRequestListenerServletRequestAttributeListenerAsyncListener

 

8.4.1ServletRequestListener

ServletRequestListenerServletRequest的创建和销毁做出响应。在Servlet容器中是通过池来重用ServletRequest的,创建ServletRequest花费的时间相当于从池中获取它的时间,ServletRequest销毁时间则相当于它返回到池中的时间。

ServletRequestListener接口定义了两个方法:签名如下:

void requestInitialized(ServletRequestEvent event)

void requestDestroyed(ServletRequestEvent event)

创建ServletRequest时会调用requestInitialized方法,ServletRequest被销毁时会调用requestDestroyed方法。这两个方法都会收到一个ServletRequestEvent,通过调用getServletRequest方法,可以从中获取到响应的ServletRequest实例

ServletRequest getServletRequest()

此外,ServletRequestEvent接口还定义了返回ServletContextgetServletContext方法,签名如下:

ServletContext getServletContext()

下面的这个例子是计算ServletRequest创建到销毁之间的时间差,从而准确得出执行请求所花费的时间。

package app08a.listener;

import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;

public class PerfStatListener implements ServletRequestListener{

	@Override
	public void requestDestroyed(ServletRequestEvent sre) {
		// TODO Auto-generated method stub
		ServletRequest servletRequest = sre.getServletRequest() ;
		Long start = (Long)servletRequest.getAttribute("start") ;
		Long end = System.nanoTime() ;
		HttpServletRequest httpServletRequest = (HttpServletRequest)servletRequest ;
		String uri = httpServletRequest.getRequestURI() ;
		System.out.println("time taken to execute " + uri + ":" + ((end-start)/100) + "microseconds");
	}

	@Override
	public void requestInitialized(ServletRequestEvent sre) {
		// TODO Auto-generated method stub
		ServletRequest servletRequest = sre.getServletRequest() ;
		servletRequest.setAttribute("start", System.nanoTime());
	}
	
}



nanoTime方法返回一个表示任意时间的long。这个返回值与任何系统概念或者壁钟的时间无关,但是在同一台JVM中得到的两个返回值,最适合用来计算第一个nanoTimes调用和第二个调用之间过了多长时间。


8.4.2ServletRequestAttributeListener

但在ServletRequest中添加、删除或者替换某个属性时,会调用ServletRequestAttributeListenerServletRequestAttributeListener接口中定义了3个方法:attributeAddedattributeReplacedattributeRemoved,定义如下:

void attributeAdded(ServletRequestAttributeEvent event)

void attributeReplaced(ServletRequestAttributeEvent  event)

void attributeRemoved(ServletRequestAttributeEvent  event)

所有方法都会收到一个ServletRequestAttributeEvent 实例。ServletRequestAttributeEvent 类通过getNamegetValue方法暴露有关的属性:

java.lang.String getName()

java.lang.Object getValue()


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值