一、定義: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>標籤)。