關於Listener詳解
ServletContextListener
ServletContextListener接口能夠監聽ServletContext對象的生命周期,實際上就是監聽Web應用的生命周期。當Servlet容器啟動或終止Web應用時,會觸發ServletContextEvent事件,該事件由ServletContextListener來處理。在ServletContextListener接口中定義了處理ServletContextEvent事件的兩個方法:
contextInitialized (ServletContextEvent event)
當Servlet容器啟動Web應用時調用該方法。在調用完該方法之后,容器再對Filter 初始化,並且對那些在Web 應用啟動時就需要被初始化的Servlet 進行初始化。用途:Web服務器啟動時加載數據到內存中…………..
contextDestroyed(ServletContextEvent event)
當Servlet 容器終止Web 應用時調用該方法。在調用該方法之前,容器會先銷毀所有的Servlet 和Filter 過濾器。
public ServletContext getServletContext();//ServletContextEvent事件:取得一個ServletContext(application)對象
HttpSessionListener
Session創建事件發生在每次一個新的session創建的時候,類似地Session失效事件發生在每次一個Session失效的時候。對Session的整體狀態的監聽。對每一個正在訪問的用戶,J2EE應用服務器會為其建立一個對應的HttpSession對象。當一個瀏覽器第一次訪問網站的時候,J2EE應用服務器會新建一個HttpSession對象,並觸發 HttpSession創建事件,如果注冊了HttpSessionListener事件監聽器,則會調用HttpSessionListener事件監聽器的sessionCreated方法。相反,當這個瀏覽器訪問結束超時的時候,J2EE應用服務器會銷毀相應的HttpSession對象,觸發 HttpSession銷毀事件,同時調用所注冊HttpSessionListener事件監聽器的sessionDestroyed方法。
在 HttpSessionListener接口中定義了處理HttpSessionEvent 事件的兩個方法:
sessionCreated(HttpSessionEvent event);//session創建
sessionDestroyed(HttpSessionEvent event);//session銷毀
HttpSession getSession();//取得當前 sessionHttpSessionEvent事件
session的銷毀有兩種情況:
1、session超時,web.xml配置:
<session-config>
<session-timeout>120</session-timeout><!--120分鍾后超時銷毀-->
</session-config>
2、手工使session失效
public void invalidate();//使session失效方法。session.invalidate();
ServletRequestListener
用於對Request請求進行監聽(創建、銷毀)。
void requestInitialized(ServletRequestEvent sre);//request初始化
void requestDestroyed(ServletRequestEvent sre);//request銷毀
//ServletRequestEvent事件:
ServletRequest getServletRequest();//取得一個ServletRequest對象
ServletContext getServletContext();//得一個ServletContext(application)對象
在web.xml中配置
Listener配置信息必須在Filter和Servlet配置之前,Listener的初始化(ServletContentListener初始化)比Servlet和Filter都優先,而銷毀比Servlet和Filter都慢。
<listener>
<listener-class>com.listener.class</listener-class>
</listener>
Listener應用實例
1、利用HttpSessionListener統計最多在線用戶人數
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class HttpSessionListenerImpl implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent event) {
ServletContext app = event.getSession().getServletContext();
int count = Integer.parseInt(app.getAttribute("onLineCount").toString());
count++;
app.setAttribute("onLineCount", count);
int maxOnLineCount = Integer.parseInt(app.getAttribute("maxOnLineCount").toString());
if (count > maxOnLineCount) {
//記錄最多人數是多少
app.setAttribute("maxOnLineCount", count);
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//記錄在那個時刻達到上限
app.setAttribute("date", df.format(new Date()));
}
}
//session注銷、超時時候調用,停止tomcat不會調用
public void sessionDestroyed(HttpSessionEvent event) {
ServletContext app = event.getSession().getServletContext();
int count = Integer.parseInt(app.getAttribute("onLineCount").toString());
count--;
app.setAttribute("onLineCount", count);
}
}
2、Spring使用ContextLoaderListener加載ApplicationContext配置信息
ContextLoaderListener的作用就是啟動Web容器時,自動裝配ApplicationContext的配置信息。因為它實現了ServletContextListener這個接口,在web.xml配置這個監聽器,啟動容器時,就會默認執行它實現的方法。
ContextLoaderListener如何查找ApplicationContext.xml的配置位置以及配置多個xml:如果在web.xml中不寫任何參數配置信息,默認的路徑是"/WEB-INF/applicationContext.xml",在WEB-INF目錄下創建的xml文件的名稱必須是applicationContext.xml(在MyEclipse中把xml文件放置在src目錄下)。如果是要自定義文件名可以在web.xml里加入contextConfigLocation這個context參數。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext-*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
3、Spring使用Log4jConfigListener配置Log4j日志
Spring使用Log4jConfigListener的好處:
動態的改變記錄級別和策略,不需要重啟Web應用。把log文件定在 /WEB-INF/logs/ 而不需要寫絕對路徑。因為系統把web目錄的路徑壓入一個叫webapp.root的系統變量。這樣寫log文件路徑時不用寫絕對路徑了。可以把log4j.properties和其他properties一起放在/WEB-INF/ ,而不是Class-Path。
設置log4jRefreshInterval時間,開一條watchdog線程每隔段時間掃描一下配置文件的變化。
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>webapp.root</param-value>
<!-- 用於定位log文件輸出位置在web應用根目錄下,log4j配置文件中寫輸出位置:log4j.appender.FILE.File=${project.root}/logs/project.log -->
</context-param>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:log4j.properties</param-value><!-- 載入log4j配置文件 -->
</context-param>
<context-param>
<param-name>log4jRefreshInterval</param-name>
<param-value>60000</param-value>
<!--Spring刷新Log4j配置文件的間隔60秒,單位為millisecond-->
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
4、Spring使用IntrospectorCleanupListener清理緩存
這個監聽器的作用是在web應用關閉時刷新JDK的JavaBeans的Introspector緩存,以確保Web應用程序的類加載器以及其加載的類正確的釋放資源。如果JavaBeans的Introspector已被用來分析應用程序類,系統級的Introspector緩存將持有這些類的一個硬引用。因此,這些類和Web應用程序的類加載器在Web應用程序關閉時將不會被垃圾收集器回收!而IntrospectorCleanupListener則會對其進行適當的清理,已使其能夠被垃圾收集器回收。唯一能夠清理Introspector的方法是刷新整個Introspector緩存,沒有其他辦法來確切指定應用程序所引用的類。這將刪除所有其他應用程序在服務器的緩存的Introspector結果。
在使用Spring內部的bean機制時,不需要使用此監聽器,因為Spring自己的introspection results cache將會立即刷新被分析過的JavaBeans Introspector cache,而僅僅會在應用程序自己的ClassLoader里面持有一個cache。雖然Spring本身不產生泄漏,注意,即使在Spring框架的類本身駐留在一個“共同”類加載器(如系統的ClassLoader)的情況下,也仍然應該使用使用IntrospectorCleanupListener。在這種情況下,這個IntrospectorCleanupListener將會妥善清理Spring的introspection cache。
應用程序類,幾乎不需要直接使用JavaBeans Introspector,所以,通常都不是Introspector resource造成內存泄露。相反,許多庫和框架,不清理Introspector,例如: Struts和Quartz。
需要注意的是一個簡單Introspector泄漏將會導致整個Web應用程序的類加載器不會被回收!這樣做的結果,將會是在web應用程序關閉時,該應用程序所有的靜態類資源(比如:單實例對象)都沒有得到釋放。而導致內存泄露的根本原因其實並不是這些未被回收的類!
注意:IntrospectorCleanupListener應該注冊為web.xml中的第一個Listener,在任何其他Listener之前注冊,比如在Spring's ContextLoaderListener注冊之前,才能確保IntrospectorCleanupListener在Web應用的生命周期適當時機生效。
<!-- memory clean -->
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>