現在來說說Servlet的監聽器Listener,它是實現了javax.servlet.ServletContextListener 接口的服務器端程序,它也是隨web應用的啟動
而啟動,只初始化一次,隨web應用的停止而銷毀。主要作用是:做一些初始化的內容添加工作、設置一些基本的內容、比如一些參數或者是一些
固定的對象等等。首先來看一下ServletContextListener接口的源代碼:
public abstract interface ServletContextListener extends EventListener{ public abstract void contextInitialized(ServletContextEvent paramServletContextEvent); public abstract void contextDestroyed(ServletContextEvent paramServletContextEvent); }
根據ServletContextListener監聽器對數據庫連接池DataSource的初始化演示它的使用:ListenerWW.java
package listener; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; /** * 現在來說說Servlet的監聽器Listener,它是實現了javax.servlet.ServletContextListener 接口的 * 服務器端程序,它也是隨web應用的啟動而啟動,只初始化一次,隨web應用的停止而銷毀。主要作用是:做一些初始化 * 的內容添加工作、設置一些基本的內容、比如一些參數或者是一些固定的對象等等。 * 示例代碼:使用監聽器對數據庫連接池DataSource進行初始化 */ public class ListenerWW implements ServletContextListener { //銷毀方法 public void contextDestroyed(ServletContextEvent servletContextEvent) { ServletContext servletContext = servletContextEvent.getServletContext(); // 在整個web應用銷毀之前調用,將所有應用空間所設置的內容清空 servletContext.removeAttribute("dataSource"); System.out.println("銷毀工作完成..."); } //初始化方法 public void contextInitialized(ServletContextEvent servletContextEvent) { // 通過這個事件可以獲取整個應用的空間 ServletContext servletContext = servletContextEvent.getServletContext(); // 在整個web應用下面啟動的時候做一些初始化的內容添加工作 // 未導入對應jar包 BasicDataSource basicDataSource = new BasicDataSource(); basicDataSource.setDriverClassName("com.jdbc.Driver"); basicDataSource.setUrl("jdbc:mysqlocalhost:3306/"); basicDataSource.setUsername("root"); basicDataSource.setPassword("root"); basicDataSource.setMaxActive(10);//最大連接數 basicDataSource.setMaxIdle(5);//最大管理數 // 把 DataSource 放入ServletContext空間中, // 供整個web應用的使用(獲取數據庫連接) servletContext.setAttribute("dataSource", basicDataSource); System.out.println("應用監聽器初始化工作完成..."); System.out.println("已經創建DataSource..."); } }
配置監聽器的web.xml
<!-- 配置監聽器 --> <listener> <listener-class>listener.ListenerWW</listener-class> </listener>
監聽器在實際項目中的應用,監聽器在java web中應用的較多,比如:統計當前在線人數、自定義session掃描器。
--------------------- 應用一:統計當前在線人數 ---------------------
代碼實現:
package listener; import javax.servlet.ServletContext; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; /** * 說說Session的監聽器Listener,它是實現了javax.servlet.HttpSessionListener 接口的 * 例子:在線人數統計 * @author 旺旺 */ public class ListenerWW implements HttpSessionListener { //在線總人數 private static int onLinePersonCount = 0; //session創建 public void sessionCreated(HttpSessionEvent sessionEvent) { //獲取Servlet上下文 ServletContext servletContext = sessionEvent.getSession().getServletContext(); onLinePersonCount = (Integer) servletContext.getAttribute("onLinePersonCount"); // 如果用戶登錄,TOTAL_ONLINE_USERS自增1 onLinePersonCount++; servletContext.setAttribute("TOTAL_ONLINE_USERS", onLinePersonCount); } //session銷毀 public void sessionDestroyed(HttpSessionEvent sessionEvent) { //獲取Servlet上下文 ServletContext servletContext = sessionEvent.getSession().getServletContext(); onLinePersonCount = (Integer) servletContext.getAttribute("onLinePersonCount"); // 如果用戶登錄,TOTAL_ONLINE_USERS自增1 onLinePersonCount--; servletContext.setAttribute("TOTAL_ONLINE_USERS", onLinePersonCount); } }
再來一個例子,掃描Session,清理長時間沒有操作的用戶
監聽實例:
package listener; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Timer; 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; /** * 當網站用戶量增加時,session占用的內存會越來越大,這時session的管理,將會是一項很大的 * 系統開銷,為了高效的管理session,我們可以寫一個監聽器,定期清理掉過期的session * @author 旺旺 */ public class ListenerWW implements HttpSessionListener,ServletContextListener { // 創建一個線程安全的集合,用來存儲session List<HttpSession> sessionList = Collections.synchronizedList(new LinkedList<HttpSession>()); private Object lock = new Object(); //session創建 public void sessionCreated(HttpSessionEvent sessionEvent) { HttpSession httpSession = sessionEvent.getSession(); synchronized (lock){ sessionList.add(httpSession); } } //session銷毀 public void sessionDestroyed(HttpSessionEvent sessionEvent) { HttpSession httpSession = sessionEvent.getSession(); synchronized (lock){ sessionList.remove(httpSession); } } // web應用關閉時觸發contextDestroyed事件 public void contextDestroyed(ServletContextEvent servletContextEvent) { System.out.println("web應用關閉..."); } // web應用啟動時觸發contextInitialized事件 public void contextInitialized(ServletContextEvent servletContextEvent) { System.out.println("web應用初始化..."); // 創建定時器 Timer timer = new Timer(); // 每隔30秒就定時執行任務 timer.schedule(new WTask(sessionList,lock), 0, 1000*30); } }
定時任務處理類
package listener; import java.util.List; import java.util.ListIterator; import java.util.TimerTask; import javax.servlet.http.HttpSession; public class WTask extends TimerTask{ private List<HttpSession> list; // 存儲傳遞過來的鎖 private Object lock; // 構造方法 WTask(List<HttpSession> list, Object lock){ this.list = list; this.lock = lock; } @Override public void run() { // 考慮到多線程的情況,這里必須要同步 synchronized (lock) { ListIterator<HttpSession> sessionIterator = list.listIterator(); while(sessionIterator.hasNext()) { //五分鍾沒有訪問后台 // httpSession.getLastAccessedTime() = session的最后訪問時間 HttpSession httpSession = sessionIterator.next(); if((System.currentTimeMillis() - httpSession.getLastAccessedTime()) > 1000*60*5) { // 手動銷毀session httpSession.invalidate(); // 從集合中移除已經被銷毀的session sessionIterator.remove(); } } /*for(HttpSession httpSession : list) { //五分鍾沒有訪問后台 // httpSession.getLastAccessedTime() = session的最后訪問時間 if((System.currentTimeMillis() - httpSession.getLastAccessedTime()) > 1000*60*5) { // 手動銷毀session httpSession.invalidate(); // 從集合中移除已經被銷毀的session list.remove(httpSession); } }*/ } } }