自定义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时,服务器创建一个session 34 //但在jsp中,默认调用request.getSession()方法,创建一个session 35 //但可以在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 @Override 59 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操作时,使用迭代器的方法对集合进行crud 70 it.remove(); 71 } 72 } 73 } 74 } 75 }
最后
将SessionScanner添加至web.xml中