一、定义:Servlet事件监听器是Servlet规范中定义的一种特殊的类,它用于监听Web应用程序中的ServletContext、HttpSession和ServletRequest等域对象建立与销毁的事件,以及监听这些域对象中的属性发生修改的事件。html
二、分类java
按监听的对象可划分为:web
用于监听应用程序环境对象(ServletContext)的事件监听器浏览器
用于监听用户会话对象(HttpSession)的事件监听器服务器
用于监听请求消息对象(ServletRequest)的事件监听器session
按监听的事件类型可划分为:app
用于监听域对象自身的建立和销毁的事件监听器jsp
用于监听域对象中的属性的增长和删除的事件监听器ide
用于监听绑定到HttpSession域中的某个对象的状态的事件监听器测试
三、要点
(1)、在Servlet规范中为每种事件监听器都定义了相应的接口,在编写事件监听器程序时只需实现这些接口就能够了,Web服务器根据用户编写的事件监听器所实现的接口把它注册到相应的被监听对象上。
(2)、一个web.xml文件中能够注册多个Servlet事件监听器,Web服务器按照它们在web.xml文件中的顺序来注册和加载这些监听器。
(3)、监听器的注册和调用过程都是Web容器自动完成,当发生被监听对象的被建立、修改或销毁等事件时,Web容器将调用与之相关的监听器对象的相应方法,用户在这些方法中编写的事件处理代码当即被执行。
ServletContextListener接口用于监听表明Web应用程序中的ServletContext对象的建立和销毁的事件。该接口定义了两个事件处理方法:
public void contextInitialized(ServletContextEvent sce)
当ServletContext对象被建立时,Web容器调用contextInitialized方法,该方法接收一个ServletContextEvent类型的参数,在方法内部能够经过这个参数来得到当前被建立的ServletContext对象。
publi void contextDestroyed(ServletContextEvent sce)
当ServletContext对象被销毁时,Web容器调用contextDestroyed方法。
HttpSessionListener接口用于监听Web应用程序中的用户会话对象HttpSession的建立和销毁的事件。该接口定义了两个事件处理方法:
public void sessionCreated(HttpSessionEvent se)
每当一个HttpSession对象被建立时,Web容器都会调用sessionCreated方法,该方法接收一个HttpSessionEvent类型的参数,在方法内部能够经过这个参数来得到当前被建立的HttpSession对象。
public void sessionDestroyed(HttpSessionEvent se)
每当一个HttpSession对象被销毁时,Web容器都会调用sessionDestroyed方法。
ServletRequestListener接口用于监听表明Web应用程序中的ServletRequest对象的建立和销毁的事件。该接口定义了两个事件处理方法:
public void requestInitialized(ServletRequestEvent sre)
每当一个ServletRequest对象被建立时,Web容器都会调用requestInitalized方法,该方法接收一个ServletRequestEvent类型的参数,在方法内部能够经过这个参数来得到当前被建立的ServletRequest对象。
public void requestDestroyed(SevletRequestEvent sre)
每当一个ServletRequest对象被销毁时,Web容器都会调用requestDestroyed方法。
MyListener.java
import java.util.Date; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestListener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class MyListener implements ServletContextListener, HttpSessionListener, ServletRequestListener { @Override public void requestDestroyed(ServletRequestEvent sre) { System.out.println("ServletRequest对象被销毁了"); } @Override public void requestInitialized(ServletRequestEvent sre) { System.out.println("ServletRequest对象被建立了"); } @Override public void sessionCreated(HttpSessionEvent se) { System.out.println("HttpSession对象被建立了"); } @Override public void sessionDestroyed(HttpSessionEvent se) { System.out.println("HttpSession对象被销毁了"); } @Override public void contextDestroyed(ServletContextEvent sce) { System.out.println("ServletContext对象被销毁了"); } @Override public void contextInitialized(ServletContextEvent sce) { System.out.println("ServletContext对象被建立了"); } }
XiaohuiSession.java
import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class XiaohuiSession extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //等效于request.getSession(true),存在返回已有的,不存在则新建。 //request.getSession(false),不存在则不新建,返回null。 HttpSession session = request.getSession(); session.invalidate(); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
web.xml(对于Servlet2.3规范,<listener>元素必须位于全部的<servlet>元素以前以及全部<filter-mapping>元素以后。Servlet2.4规范,这些同级元素之间的顺序能够任意)
<listener> <listener-class>MyListener</listener-class> </listener> <!-- session超时时间为1分钟 --> <session-config> <session-timeout>1</session-timeout> </session-config> <servlet> <servlet-name>XiaohuiSession</servlet-name> <servlet-class>XiaohuiSession</servlet-class> </servlet> <servlet-mapping> <servlet-name>XiaohuiSession</servlet-name> <url-pattern>/servlet/XiaohuiSession</url-pattern> </servlet-mapping>
借此说说session与浏览器的对应关系:
(1)、session是与浏览器一一对应的,而不是与一个访问页面。
(2)、具体地说,在一个浏览器访问某个页面建立(how to createhttp://www.360doc.com/content/12/0511/12/1542811_210284774.shtml)一个session后,只要该浏览器没有关闭,无论新建窗口从新访问这个页面,仍是双击击桌面图标再打开一样的浏览器访问这个页面,在这个session的有效期(how to set 有效期?http://fengpy2009.iteye.com/blog/834717)内,不会建立新的session。浏览器仍是属于这个会话。
(3)、何为关闭浏览器?要明白:即便这个访问页面所在浏览器关闭了,但关闭这个页面所在浏览器以前从新点击桌面图标打开了一样的浏览器,这都不算关闭了浏览器。真正的关闭是:这个浏览器一个窗口的都不存在,无论在访问这个页面前打开的浏览器仍是访问以后再打开的浏览器,总之在任务栏(哪怕隐藏了)不存在该浏览器这个任务才算关闭。
(4)、若是真正关闭了浏览器(是真正关闭),从新打开浏览器访问这个页面时,哪怕旧的session没有销毁,此次访问依然会建立一个新的session,浏览器属于新的这个会话。同时也要明白:关闭浏览器不等于session被销毁,不关闭浏览器不等于session一直都存在,当session超时后就被销毁(如何不超时就销毁?session.invalidate(),见下面测试二)。
test.jsp
<body> 这是一个测试监听器的页面! <a href="servlet/XiaohuiSession">立刻销毁session?</a> </body>
测试一:
部署项目后,启动Tomcat:
直接关闭Tomcat后台,虽然ServletContext对象被销毁了,但没法看到。故意让项目Reloading(如修改某个类):
在浏览器访问test.jsp:
连续刷新几回:
1分钟之后(经过打印系统时间System.out.println(new Date())发现真的是1分钟的)
测试二:
启动Tomcat后,访问test.jsp,而后点击连接(在session超时前点击),发现session立刻被销毁:
ServletContextAttributeListener:用于监听ServletContext对象中的属性变动信息
HttpSessionAttributeListener:用于监听HttpSession对象中的属性变动信息
ServletRequestAttributeListener:用于监听ServletRequest对象中的属性变动信息
这三个接口都定义了三个方法来处理被监听对象中的属性的增长、删除和替换的事件,同一个事件在这三个接口中对应的方法名称彻底相同,只是接收参数的类型不一样。
attributeAdded方法
public void attributeAdded(ServletContextAttributeEvent scad) public void attributeAdded(HttpSessionBindingEvent se) public void attributeAdded(ServletRequestAttributeEvent srae)
attributeRemoved方法
public void attributeRemoved(ServletContextAttributeEvent scad) public void attributeRemoved(HttpSessionBindingEvent se) public void attributeRemoved(ServletRequestAttributeEvent srae)
attitudeReplaced方法
public void attitudeReplaced(ServletContextAttributeEvent scad) public void attitudeReplaced(HttpSessionBindingEvent se) public void attitudeReplaced(ServletRequestAttributeEvent srae)
MyAttributeListener.java
import javax.servlet.ServletContextAttributeEvent; import javax.servlet.ServletContextAttributeListener; import javax.servlet.ServletRequestAttributeEvent; import javax.servlet.ServletRequestAttributeListener; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; public class MyAttributeListener implements ServletContextAttributeListener, HttpSessionAttributeListener, ServletRequestAttributeListener { @Override public void attributeAdded(ServletContextAttributeEvent scae) { System.out.println("ServletContext对象中增长了一个名为" + scae.getName() + "的属性,该属性值为" + scae.getValue()); } @Override public void attributeRemoved(ServletContextAttributeEvent scae) { System.out.println("ServletContext对象中的" + scae.getName() + "的属性被删除了"); } @Override public void attributeReplaced(ServletContextAttributeEvent scae) { System.out.println("ServletContext对象中的" + scae.getName() + "属性的值由" + scae.getValue() + "替换成了" + scae.getServletContext().getAttribute(scae.getName())); } @Override public void attributeAdded(HttpSessionBindingEvent hbe) { System.out.println("HttpSession对象中增长了一个名为" + hbe.getName() + "的属性,该属性值为" + hbe.getValue()); } @Override public void attributeRemoved(HttpSessionBindingEvent hbe) { System.out.println("HttpSession对象中的" + hbe.getName() + "属性被删除了"); } @Override public void attributeReplaced(HttpSessionBindingEvent hbe) { System.out.println("HttpSession对象中的" + hbe.getName() + "属性的值由" + hbe.getValue() + "替换成了" + hbe.getSession().getAttribute(hbe.getName())); } @Override public void attributeAdded(ServletRequestAttributeEvent srae) { System.out.println("ServletRequest对象中增长了一个名为" + srae.getName() + "的属性,该属性值为" + srae.getValue()); } @Override public void attributeRemoved(ServletRequestAttributeEvent srae) { System.out.println("ServletRequest对象中的" + srae.getName() + "属性被删除了"); } @Override public void attributeReplaced(ServletRequestAttributeEvent srae) { System.out.println("ServletRequest对象中的" + srae.getName() + "属性的值由" + srae.getValue() + "替换成了" + srae.getServletRequest().getAttribute(srae.getName())); } }
web.xml
<listener> <listener-class>MyAttributeListener</listener-class> </listener>
test.jsp
<body> <h4>这是一个测试对象属性信息监听器的页面!</h4> <% getServletContext().setAttribute("username", "zhangsan"); getServletContext().setAttribute("username", "lisi"); getServletContext().removeAttribute("username"); session.setAttribute("username", "zhangsan"); session.setAttribute("username", "lisi"); session.removeAttribute("username"); request.setAttribute("username", "zhangsan"); request.setAttribute("usernmae", "lisi"); request.removeAttribute("username"); %> </body>
启动Tomcat,访问test.jsp页面:
保存到Session域中的对象能够有多种状态:绑定(保存)到Session域中、从Session域中解除绑定、随Session对象持久化(钝化)到一个存储设备中,随Session对象从一个存储设备中恢复(活化)。在Servlet规范中还定义了两个特殊的监听接口来帮助JavaBean对象了解本身在Session域中的这些状态,这两个接口分别是HttpSessionBindingListener和HttpSessionActivationListener,实现这两个接口的类不须要在web.xml文件中注册(即不须要写<listener>标签)。