使用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
- 使用shiro和redis结合,管理SessionDAO的对Session的CRUD,并源码分析
- shiro框架实现基于redis的SessionDao
- shiro源码分析篇5:结合redis实现session跨域
- shiro的会话存储/持久化SessionDAO
- shiro 减少用redis实现的自定义SessionDAO的doUpdate的调用次数
- Shiro的缓存和session管理
- 使用Spring+redis实现对session的分布式管理
- shiro SessionDao不设置CacheManager也可以使用缓存的一个问题
- Redis 对tomcat集群--session的管理
- shiro 与 redis 结合的解决方案 shiro-redis
- Shiro源码分析之两种Session的方式
- 使用redis进行基于shiro的session集群共享
- 使用redis进行基于shiro的session集群共享
- shiro 使用redis 频繁请求获取session的问题
- 使用redis进行基于shiro的session集群共享
- 使用Spring Session和Redis管理session
- 使用Spring Session和Redis管理session
- J2EE通用后台管理系统 springmvc+mybatis+nginx+shiro+redis架构的session共享
- struts2项目向springmvc迁移 之 i 还是 my? ibatis向mybatis
- [递推] BZOJ2656: [Zjoi2012]数列(sequence)
- Socket,开发哪些事
- Android 之AlarmManager应用
- java并发编程之FutureTask
- 使用shiro和redis结合,管理SessionDAO的对Session的CRUD,并源码分析
- [华为OJ--C++]001-字符串最后一个单词的长度
- FFmpeg安装打包
- IOS 音频开发
- iOS 最新版本调用相机与相册
- nginx利用proxy_cache来缓存文件
- CDN
- 可重入与不可冲入函数
- 软件测试基础知识(一)