使用shiro和redis结合,管理SessionDAO的对Session的CRUD,并源码分析
2017-02-16 14:13
696 查看
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);
}
层级结构
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 EnterpriseCacheSessionDAO
EnterpriseCacheSessionDAO extends CachingSessionDAO
CachingSessionDAO 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
*/
@Override
public 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" })
@Override
public <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 instance
redisManager.init();
// create a new cache instance
c = new RedisCache<K, V>(redisManager, keyPrefix);
// add it to the cache collection
caches.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)
自此 集成的源码分析完毕完毕
由配置文件可以知道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 EnterpriseCacheSessionDAO
EnterpriseCacheSessionDAO extends CachingSessionDAO
CachingSessionDAO 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
*/
@Override
public 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" })
@Override
public <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 instance
redisManager.init();
// create a new cache instance
c = new RedisCache<K, V>(redisManager, keyPrefix);
// add it to the cache collection
caches.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)
自此 集成的源码分析完毕完毕
相关文章推荐
- shiro源码分析篇5:结合redis实现session跨域
- linux的信号处理和实际使用(结合redis分析)
- 【Redis】Redis学习笔记02_使用Redis来管理Tomcat集群的Session
- Shiro使用和源码分析---6
- 使用redis进行基于shiro的session集群共享
- JavaWeb企业实训 简易股市自选查询分析系统(六)使用Shiro控制登录等权限管理与Spring项目整合
- SpringMVC @SessionAttributes 使用详解以及源码分析
- Shiro使用和源码分析---1
- Shiro源码分析之两种Session的方式
- Shiro使用和源码分析---4
- tomcat-redis-session管理 使用说明
- Shiro源码分析之两种Session的方式
- Shiro使用和源码分析---1
- 基于Redis实现分布式锁-Redisson使用及源码分析
- tomcat 使用redis 管理session
- Redis源码分析:内存管理
- Shiro使用和源码分析---4
- Shiro使用和源码分析---5
- 基于Redis实现分布式锁,Redisson使用及源码分析
- 基于Redis实现分布式锁,Redisson使用及源码分析