自訂session掃描器,session掃描器
為何要自訂session掃描器
由於伺服器來管理session的銷毀不怎麼靠譜,因此很多網站都會自己定義一個session掃描器來管理session的建立和銷毀。
實現思路
首先,建立一個session掃描器類SessionScanner,然後繼承HttpSessionListener,在sessionCreated方法中,擷取session,這個時候我們需要建立一個容器,用來存放session,然後繼承ServletContextListener,在contextInitialized方法(在web應用啟動時執行此方法)中定義一個定時器,將一段時間內沒有用到的session銷毀。
代碼實現如下:
1 package com.ccfdod.web.listener; 2 3 import java.util.Collections; 4 import java.util.Iterator; 5 import java.util.LinkedList; 6 import java.util.List; 7 import java.util.ListIterator; 8 import java.util.Timer; 9 import java.util.TimerTask;10 11 import javax.servlet.ServletContextEvent;12 import javax.servlet.ServletContextListener;13 import javax.servlet.http.HttpSession;14 import javax.servlet.http.HttpSessionEvent;15 import javax.servlet.http.HttpSessionListener;16 17 public class SessionScanner implements HttpSessionListener,ServletContextListener {18 19 //這裡使用Collections.synchronizedList(List<T> list)是考慮到線程並發問題,因此將容器設定為安全執行緒的20 //Collections為集合的協助類,如發現具體的集合類不能提供某些功能,可查看該協助類的方法,看是否存在該功能21 //另外使用LinkedList而不使用ArrayList的原因是ArrayList底層為資料,用來做增刪改查不適合,效率較低22 private List<HttpSession> list = Collections.synchronizedList(new LinkedList<HttpSession>());23 24 //定義一個鎖對象,用於解決線程並發時,session的添加和除去若同時進行,會引起定時器中對list的session操作時,產生迭代器並發修改異常25 private Object lock = new Object();26 public void contextInitialized(ServletContextEvent sce) {27 //這裡使用Timer作為定時器,當然也可以使用其他的28 Timer timer = new Timer();29 timer.schedule(new MyTask(list,lock), 0, 30*1000);30 }31 32 public void sessionCreated(HttpSessionEvent se) {33 //第一次調用getSession時,伺服器建立一個session34 //但在jsp中,預設調用request.getSession()方法,建立一個session35 //但可以在jsp檔案的第一行,添加session="false",這樣在訪問jsp頁面時,就不會建立session了36 HttpSession session = se.getSession();37 System.out.println(session + "被建立了!!");38 synchronized (lock) { //鎖旗標39 list.add(session);40 }41 }42 public void sessionDestroyed(HttpSessionEvent se) {43 System.out.println(se.getSession() + "被銷毀了");44 }45 46 public void contextDestroyed(ServletContextEvent sce) {47 48 }49 }50 51 class MyTask extends TimerTask{52 private List list;53 private Object lock;54 public MyTask(List list,Object lock){55 this.list = list;56 this.lock = lock;57 }58 @Override59 public void run() {60 System.out.println("定時器執行!!");61 synchronized (this.lock) {62 //ListIterator為Iterator的子類,提供了對crud操作63 ListIterator it = list.listIterator();64 while(it.hasNext()){65 HttpSession session = (HttpSession) it.next();66 if((System.currentTimeMillis()-session.getLastAccessedTime())>30*1000){67 session.invalidate();68 //list.remove(session); //迭代器並發修改異常69 //若對集合迭代,需要對集合進行crud操作時,使用迭代器的方法對集合進行crud70 it.remove();71 }72 }73 }74 }75 }
最後
將SessionScanner添加至web.xml中