自定义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中

原文地址:https://www.cnblogs.com/ccfdod/p/6288328.html