Shiro 中的 SessionDAO

SessionDAO是用于session持久化的,SessionManager只是负责session的管理,持久化的工作是由SessionDAO完成的。

Shiro 中的 SessionDAO_第1张图片
SessionDAO的继承结构

SessionDAO 接口

SessionDAO接口是Shiro中所有SessionDAO的顶级接口,给出了从持久层(一般而言是关系型数据库)操作session的标准。方法如下:

  1. Serializable create(Session session); 插入一个新的Session到持久化设备。
  2. Session readSession(Serializable sessionId) throws UnknownSessionException; 根据会话ID获取会话。
  3. void update(Session session) throws UnknownSessionException; 更新session; 如更新session最后访问时间/停止会话/设置超时时间/设置移除属性等会调用。
  4. void delete(Session session); 删除session; 当会话过期/会话停止(如用户退出时)会调用。

AbstractSessionDAO 抽象类

AbstractSessionDAO提供了SessionDAO的基本实现;

/**
 * SessionDAO中create实现; 对创建的sesion进行持久化
 * 子类doCreate方法的代理,具体的细节委托给了子类的doCreate方法
 */
public Serializable create(Session session) {
    Serializable sessionId = doCreate(session);
    verifySessionId(sessionId);
    return sessionId;
}

/**
 * 子类通过实现此方法来持久化Session
 */
protected abstract Serializable doCreate(Session session);

/**
 * 保证从doCreate返回的sessionId不是null,并且不是已经存在的.
 * 目前只实现了null校验,是否已存在没有校验
 */
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);
    }
}

如上代码所示,AbstractSessionDAO实现了SessionDaocreate方法;并把具体的创建并持久化Session工作(doCreate方法)留给子类来实现。

/**
 * SessionDAO中readSession实现; 通过sessionId从持久化设备获取session对象.
 * 子类doReadSession方法的代理,具体的获取细节委托给了子类的doReadSession方法.
 */
public Session readSession(Serializable sessionId) throws UnknownSessionException {
    Session s = doReadSession(sessionId);
    if (s == null) {
        throw new UnknownSessionException("There is no session with id [" + sessionId + "]");
    }
    return s;
}

/**
 * 子类通过实现此方法从持久化设备获取session实例
 */
protected abstract Session doReadSession(Serializable sessionId);

如上代码所示,AbstractSessionDAO实现了SessionDaoreadSession方法;并把具体的从持久化设备获取session的操作留给了子类来实现。

AbstractSessionDAO还实现了自己的sessionId生成器,负责sessionId的操作。代码如下:

/**
 * sessionId生成器
 */
private SessionIdGenerator sessionIdGenerator;

public AbstractSessionDAO() {
    // 指定JavaUuidSessionIdGenerator为默认sessionId生成器
    this.sessionIdGenerator = new JavaUuidSessionIdGenerator();    
}

/**
 * 获取sessionId生成器
 */
public SessionIdGenerator getSessionIdGenerator() {
    return sessionIdGenerator;
}

/**
 * 设置sessionId生成器
 */
public void setSessionIdGenerator(SessionIdGenerator sessionIdGenerator) {
    this.sessionIdGenerator = sessionIdGenerator;
}

/**
 * 生成一个新的sessionId, 并将它应用到session实例
 */
protected Serializable generateSessionId(Session session) {
    if (this.sessionIdGenerator == null) {
        String msg = "sessionIdGenerator attribute has not been configured.";
        throw new IllegalStateException(msg);
    }
    return this.sessionIdGenerator.generateId(session);
}

CachingSessionDAO 抽象类

CachingSessionDAO 承继自AbstractSessionDAO,并实现了CacheManagerAware接口提供了session缓存的功能。它是应用层与持久化层之间的缓存层,不用频繁请求持久化层以提升效率。

注:需要特别说明的是,CachingSessionDAO仅是提供了缓存功能,但并没有实现缓存功能,具体的缓存功能和缓存方案还需要由子类来完成。

  1. 重写AbstractSessionDAO中的create 如下:
/**
 * AbstractSessionDAO中create的重写
 * 调用父类(AbstractSessionDAO)的create方法, 然后将session缓存起来
 * 返回sessionId
 */
public Serializable create(Session session) {
    Serializable sessionId = super.create(session);    // 调用父类的create方法
    cache(session, sessionId);                        // 以sessionId作为key缓存session
    return sessionId;
}
  1. 重写AbstractSessionDAO中的readSession 如下:
/**
 * AbstractSessionDAO中readSession的重写
 * 先从缓存中获取,若没有则调用父类的readSession方法获取session
 */
public Session readSession(Serializable sessionId) throws UnknownSessionException {
    Session s = getCachedSession(sessionId);        // 从缓存中获取
    if (s == null) {
        s = super.readSession(sessionId);           // 调用父类readSession方法获取
    }
    return s;
}
  1. 实现了SessionDAO中的update方法如下:
/**
 * SessionDAO中update的实现
 * 更新session的状态
 */
public void update(Session session) throws UnknownSessionException {
    doUpdate(session);                               // 更新持久化设备中的session
    if (session instanceof ValidatingSession) {
        if (((ValidatingSession) session).isValid()) {
            cache(session, session.getId());         // 更新缓存中的session
        } else {
            uncache(session);                        // 移除缓存中的sesson
        }
    } else {
        cache(session, session.getId());
    }
}


/**
 * 由子类去实现,持久化session到EIS
 */
protected abstract void doUpdate(Session session);

update方法中,CachingSessionDAO 仅实现了缓存功能,而具体的持久化操作则留出了doUpdate抽象方法方法由子类来实现。

  1. 实现了SessionDAO中的delete方法如下:
/**
 * SessionDAO中delete的实现
 * 删除session
 */
public void delete(Session session) {
    uncache(session);                                // 从缓存中移除
    doDelete(session);                               // 从EIS中删除
}

/**
 * 由子类去实现,从EIS中删除session
 */
protected abstract void doDelete(Session session);

同样的,在delete方法中,CachingSessionDAO 也仅实现了缓存功能,而具体的持久化操作则留出了doDelete抽象方法方法由子类来实现。

  1. 实现了SessionDAO中的getActiveSessions方法如下:
/**
 * SessionDAO中getActiveSessions的实现
 * 获取所有的存活的session
 */
public Collection getActiveSessions() {
    Cache cache = getActiveSessionsCacheLazy();
    if (cache != null) {
        return cache.values();
    } else {
        return Collections.emptySet();
    }
}

MemorySessionDAO 实现类

MemorySessionDAOSessionDAO的简单内存实现。将session保存在内存中,存储结构是ConcurrentHashMap;项目中基本上用不到,就不详细说明了。

EnterpriseCacheSessionDAO 实现类

EnterpriseCacheSessionDAO继承自CachingSessionDAO,在构造器中设置了默认的缓存管理器(AbstractCacheManager)和默认的缓存实例(MapCache),实现了缓存效果。代码如下:

public EnterpriseCacheSessionDAO() {
    // 设置默认缓存器,并实例化MapCache作为cache实例
    setCacheManager(new AbstractCacheManager() {
        @Override
        protected Cache createCache(String name) throws CacheException {
            return new MapCache(name, 
                new ConcurrentHashMap());
        }
    });
}

EnterpriseCacheSessionDAO从父类继承的持久化操作方法(doReadSessiondoUpdatedoDelete)都是空实现,也就说EnterpriseCacheSessionDAO是没有实现持久化操作的,仅仅只是简单的提供了缓存实现。当然我们可以继承EnterpriseCacheSessionDAO,重写doReadSessiondoUpdatedoDelete方法来实现持久化操作。

// AbstractSessionDAO中doReadSession的重写
protected Session doReadSession(Serializable sessionId) {
    return null; 
}

// CachingSessionDAO中doUpdate的重写
protected void doUpdate(Session session) {
}

// CachingSessionDAO中doDelete的重写
protected void doDelete(Session session) {
}

总结

SessionDAO定义了从持久层操作session的标准;AbstractSessionDAO提供了SessionDAO的基础实现,如生成会话ID等;CachingSessionDAO提供了对开发者透明的session缓存的功能,只需要设置相应的 CacheManager 即可;MemorySessionDAO直接在内存中进行session维护;而EnterpriseCacheSessionDAO提供了缓存功能的session维护,默认情况下使用 MapCache 实现,内部使用ConcurrentHashMap保存缓存的会话。

因为shiro不知道我们需要将session持久化到哪里,所以只提供了MemorySessionDAO持久化到内存。

你可能感兴趣的:(Shiro 中的 SessionDAO)