1. 程式人生 > >Java三大器之監聽器(Listener)的工作原理和代碼演示

Java三大器之監聽器(Listener)的工作原理和代碼演示

invalid -c ring try local sna 高效 jdb monitor

現在來說說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);
}

下面利用監聽器對數據庫連接池DataSource的初始化演示它的使用:ListenerTest.java
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.commons.dbcp.BasicDataSource;
/**
* 現在來說說Servlet的監聽器Listener,它是實現了javax.servlet.ServletContextListener 接口的
* 服務器端程序,它也是隨web應用的啟動而啟動,只初始化一次,隨web應用的停止而銷毀。主要作用是:做一些初始化
* 的內容添加工作、設置一些基本的內容、比如一些參數或者是一些固定的對象等等。
*
* 示例代碼:使用監聽器對數據庫連接池DataSource進行初始化
*/
public class ListenerTest implements ServletContextListener{
// 應用監聽器的銷毀方法
public void contextDestroyed(ServletContextEvent servletContextEvent) {
ServletContext servletContext = servletContextEvent.getServletContext();
// 在整個web應用銷毀之前調用,將所有應用空間所設置的內容清空
servletContext.removeAttribute("dataSource");
System.out.println("銷毀工作完成...");
}
// 應用監聽器的初始化方法
public void contextInitialized(ServletContextEvent servletContextEvent) {
// 通過這個事件可以獲取整個應用的空間
// 在整個web應用下面啟動的時候做一些初始化的內容添加工作
ServletContext servletContext = servletContextEvent.getServletContext();
// 設置一些基本的內容;比如一些參數或者是一些固定的對象
// 創建DataSource對象,連接池技術 dbcp
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);//最大管理數
//bds.setMaxWait(maxWait); 最大等待時間
// 把 DataSource 放入ServletContext空間中,
// 供整個web應用的使用(獲取數據庫連接)
servletContext.setAttribute("dataSource", basicDataSource);
System.out.println("應用監聽器初始化工作完成...");
System.out.println("已經創建DataSource...");
}
}

web.xml中配置如下,很簡單:
<!-- 配置應用監聽器 -->
<listener>
<listener-class>com.ycq.ListenerTest</listener-class>
</listener>

這樣配置好了之後,以後在web應用中就可以通過ServletContext取得BasicDataSource對象,從而獲取與數據庫的連接,提高性能,方便使用。
示例代碼二:

import java.io.File;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import com.i2f.fsp.deploy.TransactionDeployer;
/**
* 監聽器隨著項目的啟動而啟動
*
*/
public class ListenerTest2 implements ServletContextListener{
// 銷毀監聽器
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("date20161020095500 :" + servletContextEvent.getServletContext());
}
public void contextInitialized(ServletContextEvent servletContextEvent) {
try{
// 獲取項目跟路徑
String basePath = servletContextEvent.getServletContext().getRealPath("/");
// D:\apache-tomcat-6.0.41\webapps\i2money\ 絕對路徑
System.out.println("basePath20161020094700 :" + basePath);
if (!(basePath.endsWith(File.separator))){
basePath = basePath + File.separator;
}
basePath = basePath + "WEB-INF" + File.separator + "classes" + File.separator;
new TransactionDeployer(basePath).deploy();
// D:\apache-tomcat-6.0.41\webapps\i2money\WEB-INF\classes\
System.out.println("basePath20161020094701 :" + basePath);
}
catch (Exception e){
e.printStackTrace();
System.exit(-1);
}
}
}

示例代碼三:
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
public class UserLogoutListener implements HttpSessionListener{
protected final Log log = LogFactory.getLog(super.getClass());
public void sessionCreated(HttpSessionEvent event){
this.log.error("session created. id = " + event.getSession().getId());
}
public void sessionDestroyed(HttpSessionEvent event){
this.log.error("session destroyed.id = " + event.getSession().getId());
HttpSession session = event.getSession();
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(session.getServletContext());
OnlineUserMonitorClient client = (OnlineUserMonitorClient)context.getBean("onlineUserMonitorClient");
client.afterSessionDestroyed(session);
}
}

監聽器在實際項目中的應用,監聽器在java web中應用的較多,比如:統計當前在線人數、自定義session掃描器。
--------------------- 應用一:統計當前在線人數 ---------------------
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
* @description HttpSessionListener監聽器實現統計網站在線人數的功能
*/
public class SessionListener implements HttpSessionListener{

public static int TOTAL_ONLINE_USERS = 0;
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
ServletContext servletContext = httpSessionEvent.getSession().getServletContext();
TOTAL_ONLINE_USERS = (Integer) servletContext.getAttribute("TOTAL_ONLINE_USERS");
// 如果用戶退出,TOTAL_ONLINE_USERS自減1
if(TOTAL_ONLINE_USERS == 0){
servletContext.setAttribute("TOTAL_ONLINE_USERS", 1);
}
else{
TOTAL_ONLINE_USERS--;
servletContext.setAttribute("TOTAL_ONLINE_USERS", TOTAL_ONLINE_USERS);
}
}

public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
ServletContext servletContext = httpSessionEvent.getSession().getServletContext();
TOTAL_ONLINE_USERS = (Integer) servletContext.getAttribute("TOTAL_ONLINE_USERS");
// 如果用戶登錄,TOTAL_ONLINE_USERS自增1
if(TOTAL_ONLINE_USERS == 0){
servletContext.setAttribute("TOTAL_ONLINE_USERS", 1);
}
else{
TOTAL_ONLINE_USERS++;
servletContext.setAttribute("TOTAL_ONLINE_USERS", TOTAL_ONLINE_USERS);
}
}
}

--------------------- 應用二:自定義session掃描器 ---------------------
import java.util.LinkedList;
import java.util.List;
import java.util.Timer;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import jeus.util.concurrent50.Collections;
/**
* @description 當網站用戶量增加時,session占用的內存會越來越大,這時session的管理,將會是一項很大的
* 系統開銷,為了高效的管理session,我們可以寫一個監聽器,定期清理掉過期的session
*/
public class SessionScanerListener implements HttpSessionListener,ServletContextListener{
// 創建一個線程安全的集合,用來存儲session
@SuppressWarnings("unchecked")
List<HttpSession> sessionList = Collections.synchronizedList(new LinkedList<HttpSession>());
private Object lock = new Object();

public void sessionCreated(HttpSessionEvent httpSessionEvent) {
System.out.println("session 創建成功...");
HttpSession httpSession = httpSessionEvent.getSession();
synchronized (lock){
sessionList.add(httpSession);
}
}

public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
System.out.println("session 銷毀成功...");
}
// 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 MyTask(sessionList,lock), 0, 1000*30);
}
}

import java.util.List;
import java.util.ListIterator;
import java.util.TimerTask;
import javax.servlet.http.HttpSession;
/**
* 定時器,定義定時任務的具體內容
*/
public class MyTask extends TimerTask{
private List<HttpSession> list;
// 存儲傳遞過來的鎖
private Object lock;
// 構造方法
MyTask(List<HttpSession> list, Object lock){
this.list = list;
this.lock = lock;
}
@Override
public void run() {
// 考慮到多線程的情況,這裏必須要同步
synchronized (lock){
System.out.println("定時器開始執行...");
ListIterator<HttpSession> listIterator = list.listIterator();
while(listIterator.hasNext()){
HttpSession httpSession = listIterator.next();
// httpSession.getLastAccessedTime() = session的最後訪問時間
if(System.currentTimeMillis() - httpSession.getLastAccessedTime() > 1000*30){
// 手動銷毀session
httpSession.invalidate();
// 從集合中移除已經被銷毀的session
listIterator.remove();
}
}
}
}
}

Java三大器之監聽器(Listener)的工作原理和代碼演示