shiro——session会话管理

目录

 

1. 会话

1.1 Session 接口

1.2 SessionManager 会话管理

1.3 SessionListener 会话监听

2. 会话持久化

2.1 SessionDAO接口

2.2 AbstractSessionDAO类

2.3 CachingSessionDAO 类

2.4 EnterpriseCacheSessionDAO 类

2.5 MemorySessionDAO 类

3. 会话过期验证

3.1 SessionValidationScheduler接口

3.2 ExecutorServiceSessionValidationScheduler 类 


1. 会话

当用户访问我们的应用时,为了方便,将用户的信息(不止是用户信息)保存起来,下次用户访问的时候,应用就能识别出用户。shiro也提供了会话机制,可以代替Web的会话机制,Session接口是会话的核心。

1.1 Session 接口、SimpleSession类

public interface Session {
    Serializable getId();
    Date getStartTimestamp();
    Date getLastAccessTime();
    long getTimeout() throws InvalidSessionException;
    void setTimeout(long var1) throws InvalidSessionException;
    String getHost();
    void touch() throws InvalidSessionException;
    void stop() throws InvalidSessionException;
    Collection getAttributeKeys() throws InvalidSessionException;
    Object getAttribute(Object var1) throws InvalidSessionException;
    void setAttribute(Object var1, Object var2) throws InvalidSessionException;
    Object removeAttribute(Object var1) throws InvalidSessionException;
} 
  

可以看出会话可以保存的信息有:会话id,会话创建时间,最近一次访问会话的时间,会话超时时间,用户主机,键值对(用来存储一些额外自定义的数据的)。

shiro——session会话管理_第1张图片

Session接口的实现类有多个:SimpleSession(简单地实现了Session接口)

SimpleSession 简单的会话实现类,我们一般都用这个,当然还有其他的会话类。

public class SimpleSession implements ValidatingSession, Serializable {
    protected static final long MILLIS_PER_SECOND = 1000L; //这是一秒的常量
    protected static final long MILLIS_PER_MINUTE = 60000L; //一分钟的常量
    protected static final long MILLIS_PER_HOUR = 3600000L; //一小时的常量
    static int bitIndexCounter = 0;
    private static final int ID_BIT_MASK;
    private static final int START_TIMESTAMP_BIT_MASK;
    private static final int STOP_TIMESTAMP_BIT_MASK;
    private static final int LAST_ACCESS_TIME_BIT_MASK;
    private static final int TIMEOUT_BIT_MASK;
    private static final int EXPIRED_BIT_MASK;
    private static final int HOST_BIT_MASK;
    private static final int ATTRIBUTES_BIT_MASK;
    private transient Serializable id; //会话ID,就是Sessionid
    private transient Date startTimestamp; //会话开始时间
    private transient Date stopTimestamp; //会话结束时间
    private transient Date lastAccessTime; //上一次会话访问的时间
    private transient long timeout; //会话过期时间
    private transient boolean expired; //会话是否过期了
    private transient String host; //用户主机
    private transient Map attributes; //会话的存储空间,可将用户的重要信息存进会话的attributes里面
    public SimpleSession() { 
        this.timeout = 1800000L;//默认会话过期时间为30分钟
        this.startTimestamp = new Date(); //会话开始时间就是创建会话的这一刻
        this.lastAccessTime = this.startTimestamp;//初始化时,上一次会话访问时间是创建时间
    }
    public SimpleSession(String host) { //可以设置用户主机的构造方法
        this();
        this.host = host;
    }
    //省略了get、set方法
    public void touch() { //访问了一次会话,更新“上一次访问时间”
        this.lastAccessTime = new Date();
    }
    public void stop() { //停止会话,设置结束时间
        if (this.stopTimestamp == null) {
            this.stopTimestamp = new Date();
        }
    }
    protected boolean isStopped() { //判断会话是否结束
        return this.getStopTimestamp() != null;
    }
    protected void expire() { //让会话过期
        this.stop();
        this.expired = true;
    }
    public boolean isValid() { //判断会话是否有效,即判断是否过期或者结束
        return !this.isStopped() && !this.isExpired();
    }
    protected boolean isTimedOut() { //判断会话是否超时
        if (this.isExpired()) {
            return true;
        } else {
            long timeout = this.getTimeout();
            if (timeout >= 0L) {
                Date lastAccessTime = this.getLastAccessTime();
                if (lastAccessTime == null) {
                    String msg = "session.lastAccessTime for session with id [" + this.getId() + "] is null.  This value must be set at least once, preferably at least upon instantiation.  Please check the " + this.getClass().getName() + " implementation and ensure this value will be set (perhaps in the constructor?)";
                    throw new IllegalStateException(msg);
                } else {
                    long expireTimeMillis = System.currentTimeMillis() - timeout;
                    Date expireTime = new Date(expireTimeMillis);
                    return lastAccessTime.before(expireTime);
                }
            } else {
                if (log.isTraceEnabled()) {
                    log.trace("No timeout for session with id [" + this.getId() + "].  Session is not considered expired.");
                }

                return false;
            }
        }
    }
    public void validate() throws InvalidSessionException {//验证会话是否有效,无效则抛出异常
        if (this.isStopped()) {
            String msg = "Session with id [" + this.getId() + "] has been explicitly stopped.  No further interaction under this session is allowed.";
            throw new StoppedSessionException(msg);
        } else if (this.isTimedOut()) {
            this.expire();
            Date lastAccessTime = this.getLastAccessTime();
            long timeout = this.getTimeout();
            Serializable sessionId = this.getId();
            DateFormat df = DateFormat.getInstance();
            String msg = "Session with id [" + sessionId + "] has expired. Last access time: " + df.format(lastAccessTime) + ".  Current time: " + df.format(new Date()) + ".  Session timeout is set to " + timeout / 1000L + " seconds (" + timeout / 60000L + " minutes)";
            if (log.isTraceEnabled()) {
                log.trace(msg);
            }
            throw new ExpiredSessionException(msg);
        }
    }
    private Map getAttributesLazy() {//获取Attributes
        Map attributes = this.getAttributes();
        if (attributes == null) {
            attributes = new HashMap();
            this.setAttributes((Map)attributes);
        }
        return (Map)attributes;
    }
    //获取Attributes的key集合
    public Collection getAttributeKeys() throws InvalidSessionException {
        Map attributes = this.getAttributes();
        return attributes == null ? Collections.emptySet() : attributes.keySet();
    }
    public Object getAttribute(Object key) {//根据key找value
        Map attributes = this.getAttributes();
        return attributes == null ? null : attributes.get(key);
    }
    public void setAttribute(Object key, Object value) { //添加Attribute
        if (value == null) { //value为空的话,则删除该key-value
            this.removeAttribute(key);
        } else { //否则添加
            this.getAttributesLazy().put(key, value);
        }
    }
    public Object removeAttribute(Object key) { //删除Attribute
        Map attributes = this.getAttributes();
        return attributes == null ? null : attributes.remove(key);
    }
    public boolean equals(Object obj) { //判断两个Session是否是相同(根据id来)
        if (this == obj) {
            return true;
        } else if (obj instanceof SimpleSession) {
            SimpleSession other = (SimpleSession)obj;
            Serializable thisId = this.getId();
            Serializable otherId = other.getId();
            return thisId != null && otherId != null ? thisId.equals(otherId) : this.onEquals(other);
        } else {
            return false;
        }
    }
    protected boolean onEquals(SimpleSession ss) { //判断两个Session是否完全相同(内容也相同)
        boolean var10000;
        label65: {
            label58: {
                if (this.getStartTimestamp() != null) {
                    if (!this.getStartTimestamp().equals(ss.getStartTimestamp())) {
                        break label58;
                    }
                } else if (ss.getStartTimestamp() != null) {
                    break label58;
                }

                if (this.getStopTimestamp() != null) {
                    if (!this.getStopTimestamp().equals(ss.getStopTimestamp())) {
                        break label58;
                    }
                } else if (ss.getStopTimestamp() != null) {
                    break label58;
                }

                if (this.getLastAccessTime() != null) {
                    if (!this.getLastAccessTime().equals(ss.getLastAccessTime())) {
                        break label58;
                    }
                } else if (ss.getLastAccessTime() != null) {
                    break label58;
                }

                if (this.getTimeout() == ss.getTimeout() && this.isExpired() == ss.isExpired()) {
                    label60: {
                        if (this.getHost() != null) {
                            if (!this.getHost().equals(ss.getHost())) {
                                break label60;
                            }
                        } else if (ss.getHost() != null) {
                            break label60;
                        }

                        if (this.getAttributes() != null) {
                            if (this.getAttributes().equals(ss.getAttributes())) {
                                break label65;
                            }
                        } else if (ss.getAttributes() == null) {
                            break label65;
                        }
                    }
                }
            }

            var10000 = false;
            return var10000;
        }

        var10000 = true;
        return var10000;
    }

    public int hashCode() {
        Serializable id = this.getId();
        if (id != null) {
            return id.hashCode();
        } else {
            int hashCode = this.getStartTimestamp() != null ? this.getStartTimestamp().hashCode() : 0;
            hashCode = 31 * hashCode + (this.getStopTimestamp() != null ? this.getStopTimestamp().hashCode() : 0);
            hashCode = 31 * hashCode + (this.getLastAccessTime() != null ? this.getLastAccessTime().hashCode() : 0);
            hashCode = 31 * hashCode + Long.valueOf(Math.max(this.getTimeout(), 0L)).hashCode();
            hashCode = 31 * hashCode + Boolean.valueOf(this.isExpired()).hashCode();
            hashCode = 31 * hashCode + (this.getHost() != null ? this.getHost().hashCode() : 0);
            hashCode = 31 * hashCode + (this.getAttributes() != null ? this.getAttributes().hashCode() : 0);
            return hashCode;
        }
    }
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(this.getClass().getName()).append(",id=").append(this.getId());
        return sb.toString();
    }
    private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();
        short alteredFieldsBitMask = this.getAlteredFieldsBitMask();
        out.writeShort(alteredFieldsBitMask);
        if (this.id != null) {
            out.writeObject(this.id);
        }

        if (this.startTimestamp != null) {
            out.writeObject(this.startTimestamp);
        }

        if (this.stopTimestamp != null) {
            out.writeObject(this.stopTimestamp);
        }

        if (this.lastAccessTime != null) {
            out.writeObject(this.lastAccessTime);
        }

        if (this.timeout != 0L) {
            out.writeLong(this.timeout);
        }

        if (this.expired) {
            out.writeBoolean(this.expired);
        }

        if (this.host != null) {
            out.writeUTF(this.host);
        }

        if (!CollectionUtils.isEmpty(this.attributes)) {
            out.writeObject(this.attributes);
        }

    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        short bitMask = in.readShort();
        if (isFieldPresent(bitMask, ID_BIT_MASK)) {
            this.id = (Serializable)in.readObject();
        }

        if (isFieldPresent(bitMask, START_TIMESTAMP_BIT_MASK)) {
            this.startTimestamp = (Date)in.readObject();
        }

        if (isFieldPresent(bitMask, STOP_TIMESTAMP_BIT_MASK)) {
            this.stopTimestamp = (Date)in.readObject();
        }

        if (isFieldPresent(bitMask, LAST_ACCESS_TIME_BIT_MASK)) {
            this.lastAccessTime = (Date)in.readObject();
        }

        if (isFieldPresent(bitMask, TIMEOUT_BIT_MASK)) {
            this.timeout = in.readLong();
        }

        if (isFieldPresent(bitMask, EXPIRED_BIT_MASK)) {
            this.expired = in.readBoolean();
        }

        if (isFieldPresent(bitMask, HOST_BIT_MASK)) {
            this.host = in.readUTF();
        }

        if (isFieldPresent(bitMask, ATTRIBUTES_BIT_MASK)) {
            this.attributes = (Map)in.readObject();
        }

    }

    private short getAlteredFieldsBitMask() {
        int bitMask = 0;
        int bitMask = this.id != null ? bitMask | ID_BIT_MASK : bitMask;
        bitMask = this.startTimestamp != null ? bitMask | START_TIMESTAMP_BIT_MASK : bitMask;
        bitMask = this.stopTimestamp != null ? bitMask | STOP_TIMESTAMP_BIT_MASK : bitMask;
        bitMask = this.lastAccessTime != null ? bitMask | LAST_ACCESS_TIME_BIT_MASK : bitMask;
        bitMask = this.timeout != 0L ? bitMask | TIMEOUT_BIT_MASK : bitMask;
        bitMask = this.expired ? bitMask | EXPIRED_BIT_MASK : bitMask;
        bitMask = this.host != null ? bitMask | HOST_BIT_MASK : bitMask;
        bitMask = !CollectionUtils.isEmpty(this.attributes) ? bitMask | ATTRIBUTES_BIT_MASK : bitMask;
        return (short)bitMask;
    }

    private static boolean isFieldPresent(short bitMask, int fieldBitMask) {
        return (bitMask & fieldBitMask) != 0;
    }

    static {
        ID_BIT_MASK = 1 << bitIndexCounter++;
        START_TIMESTAMP_BIT_MASK = 1 << bitIndexCounter++;
        STOP_TIMESTAMP_BIT_MASK = 1 << bitIndexCounter++;
        LAST_ACCESS_TIME_BIT_MASK = 1 << bitIndexCounter++;
        TIMEOUT_BIT_MASK = 1 << bitIndexCounter++;
        EXPIRED_BIT_MASK = 1 << bitIndexCounter++;
        HOST_BIT_MASK = 1 << bitIndexCounter++;
        ATTRIBUTES_BIT_MASK = 1 << bitIndexCounter++;
    }
}
 
  

1.2 SessionManager 会话管理

shiro——session会话管理_第2张图片

SessionManager 接口,提供两个方法,start 创建并启动一个会话,根据SessionKey获取会话,Key其实就是会话id,id就是能够唯一标识用户的一个数据,并非一定要是数字。

public interface SessionManager {
    Session start(SessionContext var1);
    Session getSession(SessionKey var1) throws SessionException;
}

1.3 SessionListener 会话监听

一个接口,一个实现类,比较简单。

SessionListener 接口源码:

public interface SessionListener {
    void onStart(Session var1); //创建一个Session的时候执行
    void onStop(Session var1); //会话退出或者过期执行
    void onExpiration(Session var1); //会话过期时执行
}

SessionListenerAdapter 类源码:

public class SessionListenerAdapter implements SessionListener {
    public SessionListenerAdapter() {}
    public void onStart(Session session) {}
    public void onStop(Session session) {}
    public void onExpiration(Session session) {}
}

两种方式:实现接口SessionListener,继承类SessionListenerAdapter。

1. 实现接口SessionListener,就要实现三个方法,没得选。 2. 继承类SessionListenerAdapter,就可以选择性得去重载一两个方法。

2. 会话持久化

会话一般是放在内存中的,但是对于一个分布式集群来讲,需要共享会话,此时就需要将会话持久化。

下图中的实现类,并不是进行持久化,而是将会话存储在缓存中,或者内存中。

所以,要想将会话存到数据库里,就要自己定义一个SessionDAO。

shiro——session会话管理_第3张图片

2.1 SessionDAO接口

增、删、查、改、获取活跃会话。

public interface SessionDAO {
    Serializable create(Session var1);
    Session readSession(Serializable var1) throws UnknownSessionException;
    void update(Session var1) throws UnknownSessionException;
    void delete(Session var1);
    Collection getActiveSessions();
}

2.2 AbstractSessionDAO类

SessionIdGenerator是ID生成器(调用UUID.randomUUID().toString()生成);

虽然实现了create()方法,但是并未实现doCreate()方法,等于还是不能创建Session。

verifySessionId(Serializable sessionId) 方法是判断会话是否存在。

assignSessionId(Session session, Serializable sessionId) 方法是设置session的id为sessionId。

readSession(Serializable sessionId) 方法是根据sessionId 读取 Session。

public abstract class AbstractSessionDAO implements SessionDAO {
    private SessionIdGenerator sessionIdGenerator = new JavaUuidSessionIdGenerator();
    public AbstractSessionDAO() {}
    public SessionIdGenerator getSessionIdGenerator() {
        return this.sessionIdGenerator;
    }
    public void setSessionIdGenerator(SessionIdGenerator sessionIdGenerator) {
        this.sessionIdGenerator = sessionIdGenerator;
    }
    protected Serializable generateSessionId(Session session) {
        if (this.sessionIdGenerator == null) {
            String msg = "sessionIdGenerator attribute has not been configured.";
            throw new IllegalStateException(msg);
        } else {
            return this.sessionIdGenerator.generateId(session);
        }
    }
    public Serializable create(Session session) {
        Serializable sessionId = this.doCreate(session);
        this.verifySessionId(sessionId);
        return sessionId;
    }
    private void verifySessionId(Serializable sessionId) {
        if (sessionId == null) {
            String msg = "sessionId returned from doCreate implementation is null.  Please verify the implementation.";
            throw new IllegalStateException(msg);
        }
    }
    protected void assignSessionId(Session session, Serializable sessionId) {
        ((SimpleSession)session).setId(sessionId);
    }
    protected abstract Serializable doCreate(Session var1);
    public Session readSession(Serializable sessionId) throws UnknownSessionException {
        Session s = this.doReadSession(sessionId);
        if (s == null) {
            throw new UnknownSessionException("There is no session with id [" + sessionId + "]");
        } else {
            return s;
        }
    }
    protected abstract Session doReadSession(Serializable var1);
}

2.3 CachingSessionDAO 类

这个类一看名字,就大概知道是用缓存来存储Session。

ACTIVE_SESSION_CACHE_NAME是用来存储Session的缓存块的名字,不可修改。

CacheManager 是缓存管理器,一个接口,可以猜想这个管理就是提供很多可以操作缓存的方法。

Cache 是缓存,通过这个形式,我们可以知道:缓存其实也就是Key-Value的存储形式。

activeSessionsCacheName 这个字符串 存储的也是缓存块的名字,但是可以修改。

还有一些方法,就不做详细介绍了,一看方法的名字,就能知道是干什么的,基本上就是:创建缓存、对缓存中的会话进行增、删、查、改。 注意:实际上并没有具体实现对会话的修改和删除,这两个留着给开发者自定义。

public abstract class CachingSessionDAO extends AbstractSessionDAO implements CacheManagerAware {
    public static final String ACTIVE_SESSION_CACHE_NAME = "shiro-activeSessionCache";
    private CacheManager cacheManager;
    private Cache activeSessions;
    private String activeSessionsCacheName = "shiro-activeSessionCache";
    public CachingSessionDAO() {
    }
    public void setCacheManager(CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }
    public CacheManager getCacheManager() {
        return this.cacheManager;
    }
    public String getActiveSessionsCacheName() {
        return this.activeSessionsCacheName;
    }
    public void setActiveSessionsCacheName(String activeSessionsCacheName) {
        this.activeSessionsCacheName = activeSessionsCacheName;
    }
    public Cache getActiveSessionsCache() {
        return this.activeSessions;
    }
    public void setActiveSessionsCache(Cache cache) {
        this.activeSessions = cache;
    }
    private Cache getActiveSessionsCacheLazy() {
        if (this.activeSessions == null) {
            this.activeSessions = this.createActiveSessionsCache();
        }

        return this.activeSessions;
    }
    protected Cache createActiveSessionsCache() {
        Cache cache = null;
        CacheManager mgr = this.getCacheManager();
        if (mgr != null) {
            String name = this.getActiveSessionsCacheName();
            cache = mgr.getCache(name);
        }

        return cache;
    }
    public Serializable create(Session session) {
        Serializable sessionId = super.create(session);
        this.cache(session, sessionId);
        return sessionId;
    }
    protected Session getCachedSession(Serializable sessionId) {
        Session cached = null;
        if (sessionId != null) {
            Cache cache = this.getActiveSessionsCacheLazy();
            if (cache != null) {
                cached = this.getCachedSession(sessionId, cache);
            }
        }

        return cached;
    }
    protected Session getCachedSession(Serializable sessionId, Cache cache) {
        return (Session)cache.get(sessionId);
    }
    protected void cache(Session session, Serializable sessionId) {
        if (session != null && sessionId != null) {
            Cache cache = this.getActiveSessionsCacheLazy();
            if (cache != null) {
                this.cache(session, sessionId, cache);
            }
        }
    }
    protected void cache(Session session, Serializable sessionId, Cache cache) {
        cache.put(sessionId, session);
    }
    public Session readSession(Serializable sessionId) throws UnknownSessionException {
        Session s = this.getCachedSession(sessionId);
        if (s == null) {
            s = super.readSession(sessionId);
        }
        return s;
    }
    public void update(Session session) throws UnknownSessionException {
        this.doUpdate(session);
        if (session instanceof ValidatingSession) {
            if (((ValidatingSession)session).isValid()) {
                this.cache(session, session.getId());
            } else {
                this.uncache(session);
            }
        } else {
            this.cache(session, session.getId());
        }
    }
    protected abstract void doUpdate(Session var1);
    public void delete(Session session) {
        this.uncache(session);
        this.doDelete(session);
    }
    protected abstract void doDelete(Session var1);
    protected void uncache(Session session) {
        if (session != null) {
            Serializable id = session.getId();
            if (id != null) {
                Cache cache = this.getActiveSessionsCacheLazy();
                if (cache != null) {
                    cache.remove(id);
                }
            }
        }
    }
    public Collection getActiveSessions() {
        Cache cache = this.getActiveSessionsCacheLazy();
        return (Collection)(cache != null ? cache.values() : Collections.emptySet());
    }
}

2.4 EnterpriseCacheSessionDAO 类

在看看这个类,事实证明,确实是将会话的修改和删除留给我们开发者去做,这个类实现了CachingSessionDAO里的抽象方法,所以这个类才能被实例化。

public class EnterpriseCacheSessionDAO extends CachingSessionDAO {
    public EnterpriseCacheSessionDAO() {
        this.setCacheManager(new AbstractCacheManager() {
            protected Cache createCache(String name) throws CacheException {
                return new MapCache(name, new ConcurrentHashMap());
            }
        });
    }
    protected Serializable doCreate(Session session) {
        Serializable sessionId = this.generateSessionId(session);
        this.assignSessionId(session, sessionId);
        return sessionId;
    }
    protected Session doReadSession(Serializable sessionId) {
        return null;
    }
    protected void doUpdate(Session session) {
    }
    protected void doDelete(Session session) {
    }
}

2.5 MemorySessionDAO 类

这个类是用一个ConcurrentHashMap<>来存储Session的,这个ConcurrentHashMap<> 和 HashMap 用法一样,功能一样,只是ConcurrentHashMap<> 是多线程安全的,而HashMap<>是线程不安全的。

方法就不一一详细介绍了,基本也就是创建、删除、修改、查询等等。

public class MemorySessionDAO extends AbstractSessionDAO {
    private static final Logger log = LoggerFactory.getLogger(MemorySessionDAO.class);
    private ConcurrentMap sessions = new ConcurrentHashMap();
    public MemorySessionDAO() {
    }
    protected Serializable doCreate(Session session) {
        Serializable sessionId = this.generateSessionId(session);
        this.assignSessionId(session, sessionId);
        this.storeSession(sessionId, session);
        return sessionId;
    }
    protected Session storeSession(Serializable id, Session session) {
        if (id == null) {
            throw new NullPointerException("id argument cannot be null.");
        } else {
            return (Session)this.sessions.putIfAbsent(id, session);
        }
    }
    protected Session doReadSession(Serializable sessionId) {
        return (Session)this.sessions.get(sessionId);
    }
    public void update(Session session) throws UnknownSessionException {
        this.storeSession(session.getId(), session);
    }
    public void delete(Session session) {
        if (session == null) {
            throw new NullPointerException("session argument cannot be null.");
        } else {
            Serializable id = session.getId();
            if (id != null) {
                this.sessions.remove(id);
            }
        }
    }
    public Collection getActiveSessions() {
        Collection values = this.sessions.values();
        return (Collection)(CollectionUtils.isEmpty(values) ? Collections.emptySet() : Collections.unmodifiableCollection(values));
    }
}

3. 会话过期验证

Shiro 提供了会话验证调度器,用于定期的验证会话是否已过期,如果过期将停止会话;出于性能考虑,一般情况下都是获取会话时来验证会话是否过期并停止会话的;但是如在web环境中,如果用户不主动退出是不知道会话是否过期的,因此需要定期的检测会话是否过期,Shiro 提供了会话验证调度器SessionValidationScheduler来做这件事情。

3.1 SessionValidationScheduler接口

Scheduler 单词的意思就是 行程,计划,所以这个接口的意思就是:周期性地、按计划性地对会话进行验证。

public interface SessionValidationScheduler {
    boolean isEnabled(); //返回当前验证器是否可用,true为可用,false为不可用
    void enableSessionValidation(); //将验证器设置为可用
    void disableSessionValidation(); //将验证器设置为不可用
}

3.2 ExecutorServiceSessionValidationScheduler 类 

ValidatingSessionManager 是接口,验证会话管理器,可以调用方法validateSessions() 进行验证。

ScheduledExecutorService 是接口,可以对认证线程进行操作管理。

interval 是验证的间隔时间。

threadNamePrefix 是验证线程的线程名。

启动一个线程去验证session。

实现了 disableSessionValidation()  方法 和 eableSessionValidation()  方法。

public class ExecutorServiceSessionValidationScheduler implements SessionValidationScheduler, Runnable {
    private static final Logger log = LoggerFactory.getLogger(ExecutorServiceSessionValidationScheduler.class);
    ValidatingSessionManager sessionManager;
    private ScheduledExecutorService service;
    private long interval = 3600000L;
    private boolean enabled = false;
    private String threadNamePrefix = "SessionValidationThread-";
    public ExecutorServiceSessionValidationScheduler() { }
    public ExecutorServiceSessionValidationScheduler(ValidatingSessionManager sessionManager) {
        this.sessionManager = sessionManager;
    }
    public ValidatingSessionManager getSessionManager() {
        return this.sessionManager;
    }
    public void setSessionManager(ValidatingSessionManager sessionManager) {
        this.sessionManager = sessionManager;
    }
    public long getInterval() {
        return this.interval;
    }
    public void setInterval(long interval) {
        this.interval = interval;
    }
    public boolean isEnabled() {
        return this.enabled;
    }
    public void setThreadNamePrefix(String threadNamePrefix) {
        this.threadNamePrefix = threadNamePrefix;
    }
    public String getThreadNamePrefix() {
        return this.threadNamePrefix;
    }
    public void enableSessionValidation() {
        if (this.interval > 0L) {
            this.service = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
                private final AtomicInteger count = new AtomicInteger(1);
                public Thread newThread(Runnable r) {
                    Thread thread = new Thread(r);
                    thread.setDaemon(true);                          
 thread.setName(ExecutorServiceSessionValidationScheduler.this.threadNamePrefix + this.count.getAndIncrement());
                    return thread;
                }
            });
            this.service.scheduleAtFixedRate(this, this.interval, this.interval, TimeUnit.MILLISECONDS);
        }
        this.enabled = true;
    }
    public void run() {
        if (log.isDebugEnabled()) {
            log.debug("Executing session validation...");
        }
        long startTime = System.currentTimeMillis();
        this.sessionManager.validateSessions();
        long stopTime = System.currentTimeMillis();
        if (log.isDebugEnabled()) {
            log.debug("Session validation completed successfully in " + (stopTime - startTime) + " milliseconds.");
        }
    }
    public void disableSessionValidation() {
        if (this.service != null) {
            this.service.shutdownNow();
        }
        this.enabled = false;
    }
}

 

你可能感兴趣的:(shiro)