且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

第八章_监听器

更新时间:2022-10-10 07:47:29

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

[html] view plain copy  print?
  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  
  2. <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>  
  3. <html>  
  4.   <head>  
  5.     <title>My JSP 'countries.jsp' starting page</title>  
  6.   </head>  
  7.     
  8.   <body>  
  9.     We operate in these countries:  
  10.     <ul>  
  11.         <c:forEach items="${countries}" var="country">  
  12.             <li>${country.value}</li>  
  13.         </c:forEach>  
  14.     </ul>  
  15.   </body>  
  16. </html>  

AppListener.java

[html] view plain copy  print?
  1. package app08a.listener;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5.   
  6. import javax.servlet.ServletContext;  
  7. import javax.servlet.ServletContextEvent;  
  8. import javax.servlet.ServletContextListener;  
  9. import javax.servlet.annotation.WebListener;  
  10. @WebListener  
  11. public class AppListener implements ServletContextListener{  
  12.   
  13.     @Override  
  14.     public void contextDestroyed(ServletContextEvent sce) {  
  15.     }  
  16.   
  17.     @Override  
  18.     public void contextInitialized(ServletContextEvent sce) {  
  19.         System.out.println("ServletContextListener started");  
  20.         ServletContext servletContext = sce.getServletContext() ;  
  21.         Map<String,String> countries = new HashMap<String,String>() ;  
  22.         countries.put("ca", "Canada") ;  
  23.         countries.put("us", "United States") ;  
  24.         servletContext.setAttribute("countries", countries) ;  
  25.     }  
  26.   
  27. }  

第八章_监听器


第八章_监听器


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

[html] view plain copy  print?
  1. package app08a.listener;  
  2.   
  3. import java.util.concurrent.atomic.AtomicInteger;  
  4.   
  5. import javax.servlet.ServletContext;  
  6. import javax.servlet.ServletContextEvent;  
  7. import javax.servlet.ServletContextListener;  
  8. import javax.servlet.http.HttpSession;  
  9. import javax.servlet.http.HttpSessionEvent;  
  10. import javax.servlet.http.HttpSessionListener;  
  11.   
  12. public class SessionListener implements HttpSessionListener,ServletContextListener{  
  13.   
  14.     @Override  
  15.     public void contextDestroyed(ServletContextEvent sce) {  
  16.     }  
  17.   
  18.     @Override  
  19.     public void contextInitialized(ServletContextEvent sce) {  
  20.         ServletContext servletContext = sce.getServletContext() ;  
  21.         servletContext.setAttribute("userController", new AtomicInteger());  
  22.     }  
  23.   
  24.     @Override  
  25.     public void sessionCreated(HttpSessionEvent se) {  
  26.         HttpSession session = se.getSession() ;  
  27.         ServletContext servletContext = session.getServletContext() ;  
  28.         AtomicInteger userCounter = (AtomicInteger)servletContext.getAttribute("userController") ;  
  29.         int userCount = userCounter.incrementAndGet() ;  
  30.         System.out.println("userCount increment to :" + userCount);  
  31.     }  
  32.   
  33.     @Override  
  34.     public void sessionDestroyed(HttpSessionEvent se) {  
  35.         HttpSession session = se.getSession() ;  
  36.         ServletContext servletContext = session.getServletContext() ;  
  37.         AtomicInteger userCounter = (AtomicInteger)servletContext.getAttribute("userController") ;  
  38.         int userCount = userCounter.decrementAndGet() ;  
  39.         System.out.println("userCount decrement to :" + userCount);  
  40.     }  
  41.   
  42. }  
countries.jsp
[html] view plain copy  print?
  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  
  2. <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>  
  3. <html>  
  4.   <head>  
  5.     <title>My JSP 'countries.jsp' starting page</title>  
  6.   </head>  
  7.     
  8.   <body>  
  9.     We operate in these countries:  
  10.     <ul>  
  11.         <c:forEach items="${countries}" var="country">  
  12.             <li>${country.value}</li>  
  13.         </c:forEach>  
  14.     </ul>  
  15.   </body>  
  16. </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取消绑定,它的实现就可以释放占用的资源。

[html] view plain copy  print?
  1. package app08a.model;  
  2.   
  3. import javax.servlet.http.HttpSessionBindingEvent;  
  4. import javax.servlet.http.HttpSessionBindingListener;  
  5.   
  6. public class Product implements HttpSessionBindingListener{  
  7.     private String id ;  
  8.     private String name ;  
  9.     private double price ;  
  10.   
  11.     public String getId() {  
  12.         return id;  
  13.     }  
  14.   
  15.     public void setId(String id) {  
  16.         this.id = id;  
  17.     }  
  18.   
  19.     public String getName() {  
  20.         return name;  
  21.     }  
  22.   
  23.     public void setName(String name) {  
  24.         this.name = name;  
  25.     }  
  26.   
  27.     public double getPrice() {  
  28.         return price;  
  29.     }  
  30.   
  31.     public void setPrice(double price) {  
  32.         this.price = price;  
  33.     }  
  34.   
  35.     @Override  
  36.     public void valueBound(HttpSessionBindingEvent event) {  
  37.         String attributeName = event.getName() ;  
  38.         System.out.println(attributeName + " valueBound");  
  39.     }  
  40.   
  41.     @Override  
  42.     public void valueUnbound(HttpSessionBindingEvent event) {  
  43.         String attributeName = event.getName() ;  
  44.         System.out.println(attributeName + " valueUnbound");  
  45.     }  
  46.   
  47. }  


当监听器与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创建到销毁之间的时间差,从而准确得出执行请求所花费的时间。

[html] view plain copy  print?
  1. package app08a.listener;  
  2.   
  3. import javax.servlet.ServletRequest;  
  4. import javax.servlet.ServletRequestEvent;  
  5. import javax.servlet.ServletRequestListener;  
  6. import javax.servlet.http.HttpServletRequest;  
  7.   
  8. public class PerfStatListener implements ServletRequestListener{  
  9.   
  10.     @Override  
  11.     public void requestDestroyed(ServletRequestEvent sre) {  
  12.         // TODO Auto-generated method stub  
  13.         ServletRequest servletRequest = sre.getServletRequest() ;  
  14.         Long start = (Long)servletRequest.getAttribute("start") ;  
  15.         Long end = System.nanoTime() ;  
  16.         HttpServletRequest httpServletRequest = (HttpServletRequest)servletRequest ;  
  17.         String uri = httpServletRequest.getRequestURI() ;  
  18.         System.out.println("time taken to execute " + uri + ":" + ((end-start)/100) + "microseconds");  
  19.     }  
  20.   
  21.     @Override  
  22.     public void requestInitialized(ServletRequestEvent sre) {  
  23.         // TODO Auto-generated method stub  
  24.         ServletRequest servletRequest = sre.getServletRequest() ;  
  25.         servletRequest.setAttribute("start", System.nanoTime());  
  26.     }  
  27.       
  28. }  

第八章_监听器

第八章_监听器

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()