使用shiro和redis结合,管理SessionDAO的对Session的CRUD,并源码分析

来源:互联网 发布:广西星巢网络 编辑:程序博客网 时间:2024/05/18 03:08

SessionDAO的作用是为Session提供CRUD并进行持久化的一个shiro组件,将集成redis缓存进行开发

由配置文件可以知道sessionManager需要注入一个sessionDao

<!-- 自定义会话管理配置 --><bean id="sessionManager" class="com.dq.shiro.security.SessionManager"> <property name="sessionDAO" ref="sessionDAO"/><!-- 配置会话监听器 --><property name="sessionListeners" ref="mySessionListener" />  <!-- 会话超时时间,单位:毫秒  --><property name="globalSessionTimeout" value="${session.sessionTimeout}"/><!-- 定时清理失效会话, 清理用户直接关闭浏览器造成的孤立会话   --><property name="sessionValidationInterval" value="${session.sessionTimeoutClean}"/><!--  <property name="sessionValidationSchedulerEnabled" value="false"/> --> <property name="sessionValidationSchedulerEnabled" value="true"/> <property name="sessionIdCookie" ref="sessionIdCookie"/><property name="sessionIdCookieEnabled" value="true"/></bean>
自定义的SessionManager的继承关系为

SessionManager extends DefaultWebSessionManager DefaultWebSessionManager extends DefaultSessionManager
我们能够在DefaultSessionManager中发现我们注入的SessionDAO

public class DefaultSessionManager extends AbstractValidatingSessionManager implements CacheManagerAware {    //TODO - complete JavaDoc    private static final Logger log = LoggerFactory.getLogger(DefaultSessionManager.class);    private SessionFactory sessionFactory;    protected SessionDAO sessionDAO;  //todo - move SessionDAO up to AbstractValidatingSessionManager?

DefaultSessionManager所有对session的crud的操作都是由sessionDAO执行的,DefaultSessionManager中对应session操作的方法有

create,delete,update等,比如create

    protected void create(Session session) {        if (log.isDebugEnabled()) {            log.debug("Creating new EIS record for new session instance [" + session + "]");        }        sessionDAO.create(session);    }    @Override    protected void onStop(Session session) {        if (session instanceof SimpleSession) {            SimpleSession ss = (SimpleSession) session;            Date stopTs = ss.getStopTimestamp();            ss.setLastAccessTime(stopTs);        }        onChange(session);    }
    @Override    protected void afterStopped(Session session) {        if (isDeleteInvalidSessions()) {            delete(session);        }    }    protected void onExpiration(Session session) {        if (session instanceof SimpleSession) {            ((SimpleSession) session).setExpired(true);        }        onChange(session);    }
这样我们就理清了SessionManager和sessionDAO的关系,SessionManager注入sessionDAO,实现Session的CRUD

层级结构

ShiroFilterFactoryBean

-->securityManager

-->realm

-->cacheManager

-->rememberMeManager

-->sessionManager

-->sessionDAO
-->cacheManager

SessionDAO的配置

<!-- 自定义Session存储容器 --><bean id="sessionDAO" class="com.dq.shiro.security.CacheSessionDAO"><property name="sessionIdGenerator" ref="sessionIdGen" /><property name="activeSessionsCacheName" value="activeSessionsCache" /><property name="cacheManager" ref="shiroCacheManager" /></bean><!-- 定义授权缓存管理器 --><!-- <bean id="shiroCacheManager" class="com.minstone.common.security.shiro.cache.SessionCacheManager" // --><bean id="shiroCacheManager" class="com.dq.shiro.cache.RedisCacheManager">    <property name="redisManager" ref="redisManager" /></bean>

可以看到sessionDAO需要注入sessionIdGenerator和cacheManager
而cacheManger需要注入一个redisManager,这个redisManager是一个直接操作redisApi的类

首先说一下sessionIdGenerator这是一个比较简单的内容,就是一个SessionId的自定义生成器

首先说下sessionDAO继承结构

CacheSessionDAO extends EnterpriseCacheSessionDAOEnterpriseCacheSessionDAO extends CachingSessionDAOCachingSessionDAO extends AbstractSessionDAO

在AbstractSessionDAO 发现了注入的SessionIdGenerator,其实这个引用就是为了生成一个我们自己需要的sessionId生成方式

public abstract class AbstractSessionDAO implements SessionDAO {    /**     * Optional SessionIdGenerator instance available to subclasses via the     * {@link #generateSessionId(org.apache.shiro.session.Session)} method.     */    private SessionIdGenerator sessionIdGenerator;

再来看sessionIdGenerator的具体类SessionIdGen

public class SessionIdGen implements SessionIdGenerator {/** * @Description: TODO(Session ID 生成) * @param: @param session * @param: @return * @throws */@Overridepublic Serializable generateId(Session session) {return IdGen.uuid();}}
在CachingSessionDAO发现了注入的cacheManager

public abstract class CachingSessionDAO extends AbstractSessionDAO implements CacheManagerAware {    /**     * The default active sessions cache name, equal to {@code shiro-activeSessionCache}.     */    public static final String ACTIVE_SESSION_CACHE_NAME = "shiro-activeSessionCache";    /**     * The CacheManager to use to acquire the Session cache.     */    private CacheManager cacheManager;

在CachingSessionDAO中发现了create方法,这个方法就是DefaultSessionManager的create方法中的sessionDAO创建session的实现,
这样也证实了SessionManager和sessionDAO的联系

//CachingSessionDAO 的create    public Serializable create(Session session) {        Serializable sessionId = super.create(session);        cache(session, sessionId);        return sessionId;    }  cache(session, sessionId);这行就是操作缓存的核心,继续跟踪源码    protected void cache(Session session, Serializable sessionId) {        if (session == null || sessionId == null) {            return;        }        Cache<Serializable, Session> cache = getActiveSessionsCacheLazy();        if (cache == null) {            return;        }        cache(session, sessionId, cache);    }

我们看到了获取cache的操作getActiveSessionsCacheLazy();这些方法都是CachingSessionDAO中的方法

    private Cache<Serializable, Session> getActiveSessionsCacheLazy() {        if (this.activeSessions == null) {            this.activeSessions = createActiveSessionsCache();        }        return activeSessions;    }    protected Cache<Serializable, Session> createActiveSessionsCache() {        Cache<Serializable, Session> cache = null;        CacheManager mgr = getCacheManager();        if (mgr != null) {            String name = getActiveSessionsCacheName();            cache = mgr.getCache(name);        }        return cache;    }
重点来了 CacheManager mgr = getCacheManager();获取到了我们在SessionDAO中注入的cacheManager
这也是RedisCacheManager implements CacheManager需要实现的方法

@SuppressWarnings({ "rawtypes", "unchecked" })@Overridepublic <K, V> Cache<K, V> getCache(String name) throws CacheException {logger.debug("获取名称为: " + name + " 的RedisCache实例");Cache c = caches.get(name);if (c == null) {// initialize the Redis manager instanceredisManager.init();// create a new cache instancec = new RedisCache<K, V>(redisManager, keyPrefix);// add it to the cache collectioncaches.put(name, c);}return c;}
这里发现将redisManager当做RedisCache的key设置进来
这个RedisCache就是实现了Cache接口的实现类

public class RedisCache<K, V> implements Cache<K, V> {/** * The wrapped Jedis instance. */private RedisManager cache;/** * The Redis key prefix for the sessions */private String keyPrefix = "shiro_redis_session:";/** * Returns the Redis session keys prefix. *  * @return The prefix */public String getKeyPrefix() {return keyPrefix;

这个redisCache通过RedisManager这个直接操作Jedis的类操作


所以操作就流程就是SessionManager(DefaultWebSessionManager )去引入SessionDAO,由SessionDAO操作缓存
SessionDAO注入cacheManager
cacheManager注入redisManager
在SessionDAO create delete update等方法时(被DefaultWebSessionManager调用)
会寻求cacheManager获取到一个实现了Cache接口的Cache对象(redisCache)
由这个对象来操作redis的CRUD(redisCache引入了redisManager,使用redisManager来操作redis)
自此 集成的源码分析完毕完毕



0 0