2025年优化 shiro 多次调用 redis 的问题

优化 shiro 多次调用 redis 的问题我们常使用 Shiro redis 的组合解决集群下的 Session 共享问题 这里就不展开如何集成的问题了 在进行日常优化的过程中 我通过日志发现这么一段日志 2017 09 17 15 16 07 723 DEBUG nio 8080 exec 6 org apache shiro session mgt

大家好,我是讯享网,很高兴认识大家。
2017-09-17 15:16:07.723 -DEBUG [nio-8080-exec-6] org.apache.shiro.session.mgt.DefaultSessionManager : Creating new EIS record for new session instance [org.apache.shiro.session.mgt.SimpleSession,id=null] 2017-09-17 15:16:07.723 -DEBUG [nio-8080-exec-6] cn.bqjr.eily.shiro.spring.boot.RedisShiroSessionDAO : 创建session:74a8d2b3-7143-40f1-b7bb-abc90 2017-09-17 15:16:07.723 -DEBUG [nio-8080-exec-6] cn.bqjr.eily.shiro.spring.boot.RedisShiroSessionDAO : 获取session:74a8d2b3-7143-40f1-b7bb-abc90 2017-09-17 15:16:07.723 -DEBUG [nio-8080-exec-6] org.springframework.data.redis.core.RedisConnectionUtils : Opening RedisConnection 2017-09-17 15:16:07.723 -DEBUG [nio-8080-exec-6] org.springframework.data.redis.core.RedisConnectionUtils : Closing Redis Connection 2017-09-17 15:16:07.723 -DEBUG [nio-8080-exec-6] cn.bqjr.eily.shiro.spring.boot.RedisShiroSessionDAO : 保存session:74a8d2b3-7143-40f1-b7bb-abc90 2017-09-17 15:16:07.724 -DEBUG [nio-8080-exec-6] org.springframework.data.redis.core.RedisConnectionUtils : Opening RedisConnection 2017-09-17 15:16:07.724 -DEBUG [nio-8080-exec-6] org.springframework.data.redis.core.RedisConnectionUtils : Closing Redis Connection 2017-09-17 15:16:07.725 -DEBUG [nio-8080-exec-6] cn.bqjr.eily.shiro.spring.boot.RedisShiroSessionDAO : 获取session:74a8d2b3-7143-40f1-b7bb-abc90 2017-09-17 15:16:07.725 -DEBUG [nio-8080-exec-6] org.springframework.data.redis.core.RedisConnectionUtils : Opening RedisConnection 2017-09-17 15:16:07.725 -DEBUG [nio-8080-exec-6] org.springframework.data.redis.core.RedisConnectionUtils : Closing Redis Connection 2017-09-17 15:16:07.725 -DEBUG [nio-8080-exec-6] cn.bqjr.eily.shiro.spring.boot.RedisShiroSessionDAO : 保存session:74a8d2b3-7143-40f1-b7bb-abc90 2017-09-17 15:16:07.725 -DEBUG [nio-8080-exec-6] org.springframework.data.redis.core.RedisConnectionUtils : Opening RedisConnection 2017-09-17 15:16:07.725 -DEBUG [nio-8080-exec-6] org.springframework.data.redis.core.RedisConnectionUtils : Closing Redis Connection 2017-09-17 15:16:07.725 -DEBUG [nio-8080-exec-6] org.apache.shiro.web.session.mgt.DefaultWebSessionManager : Session ID cookie is disabled. No cookie has been set for new session with id 74a8d2b3-7143-40f1-b7bb-abc90 2017-09-17 15:16:07.725 -DEBUG [nio-8080-exec-6] cn.bqjr.eily.shiro.spring.boot.RedisShiroSessionDAO : 获取session:74a8d2b3-7143-40f1-b7bb-abc90 2017-09-17 15:16:07.725 -DEBUG [nio-8080-exec-6] org.springframework.data.redis.core.RedisConnectionUtils : Opening RedisConnection 2017-09-17 15:16:07.726 -DEBUG [nio-8080-exec-6] org.springframework.data.redis.core.RedisConnectionUtils : Closing Redis Connection 2017-09-17 15:16:07.726 -DEBUG [nio-8080-exec-6] cn.bqjr.eily.shiro.spring.boot.RedisShiroSessionDAO : 保存session:74a8d2b3-7143-40f1-b7bb-abc90 2017-09-17 15:16:07.726 -DEBUG [nio-8080-exec-6] org.springframework.data.redis.core.RedisConnectionUtils : Opening RedisConnection 2017-09-17 15:16:07.727 -DEBUG [nio-8080-exec-6] org.springframework.data.redis.core.RedisConnectionUtils : Closing Redis Connection 2017-09-17 15:16:07.727 -DEBUG [nio-8080-exec-6] cn.bqjr.eily.shiro.spring.boot.RedisShiroSessionDAO : 获取session:74a8d2b3-7143-40f1-b7bb-abc90 2017-09-17 15:16:07.727 -DEBUG [nio-8080-exec-6] org.springframework.data.redis.core.RedisConnectionUtils : Opening RedisConnection 2017-09-17 15:16:07.727 -DEBUG [nio-8080-exec-6] org.springframework.data.redis.core.RedisConnectionUtils : Closing Redis Connection 2017-09-17 15:16:07.727 -DEBUG [nio-8080-exec-6] cn.bqjr.eily.shiro.spring.boot.RedisShiroSessionDAO : 保存session:74a8d2b3-7143-40f1-b7bb-abc90 2017-09-17 15:16:07.728 -DEBUG [nio-8080-exec-6] org.springframework.data.redis.core.RedisConnectionUtils : Opening RedisConnection 2017-09-17 15:16:07.728 -DEBUG [nio-8080-exec-6] org.springframework.data.redis.core.RedisConnectionUtils : Closing Redis Connection 

讯享网
讯享网// DefaultSessionManager.class protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException { Serializable sessionId = this.getSessionId(sessionKey); if (sessionId == null) { log.debug("Unable to resolve session ID from SessionKey [{}]. Returning null to indicate a session could not be found.", sessionKey); return null; } else { Session s = this.retrieveSessionFromDataSource(sessionId); if (s == null) { String msg = "Could not find session with ID [" + sessionId + "]"; throw new UnknownSessionException(msg); } else { return s; } } } protected Session retrieveSessionFromDataSource(Serializable sessionId) throws UnknownSessionException { return this.sessionDAO.readSession(sessionId); } 

这里可以直观地看到,shiro 取得 SessionId 后直接通过 sessionDao 去获取 Session 对象了,由于我们集成了 redis,所以这里的 dao 一般是我们自定义的 RedisSessionDao 了,这就不多展开了。关键看retrieveSession方法,如何能减少单次请求内调用retrieveSessionFromDataSource的次数呢?我们惯性思维会想到首次获取到 session 后就将其缓存起来,下次再获取时就直接返回而避免再次调用 redis。这种方式需要注意的就是这个 session 的作用域问题,要避免出现不同请求间 session 对象的隔离。要实现的方法很多,比如 ThreadLocal,但是使用它咱就要考虑数据生命周期或者作用域的问题了,有没有别的更简单点的方式?

答案是必须的,在对retrieveSession方法进行 debug 的时候,我发现 sessionKey 变量的有趣之处:
WebSessionKey.png-39.5kB
讯享网在 Web 下使用 shiro 时这个 sessionKey 是 WebSessionKey 类型的,这个类有个我们很熟悉的属性:servletRequest。小伙伴们应该都灵光一现了!直接把 session 对象怼进 request 里去!那么在单次请求周期内我们都可以从 request 中取 session 了,而且请求结束后 request 被销毁,作用域和生命周期的问题都不需要我们考虑了。
显然我们要 Override 这个retrieveSession方法,为此我们需要使用自定义的 SessionManager,如下:

public class ShiroSessionManager extends DefaultWebSessionManager { / * 获取session * 优化单次请求需要多次访问redis的问题 * @param sessionKey * @return * @throws UnknownSessionException */ @Override protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException { Serializable sessionId = getSessionId(sessionKey); ServletRequest request = null; if (sessionKey instanceof WebSessionKey) { request = ((WebSessionKey) sessionKey).getServletRequest(); } if (request != null && null != sessionId) { Object sessionObj = request.getAttribute(sessionId.toString()); if (sessionObj != null) { return (Session) sessionObj; } } Session session = super.retrieveSession(sessionKey); if (request != null && null != sessionId) { request.setAttribute(sessionId.toString(), session); } return session; } } 

剩下的就是在 ShiroConfiguration 中注册这个自定义 SessionManager 即可。

参考地址:http://www.hillfly.com/2017/182.html

l

小讯
上一篇 2025-01-05 16:47
下一篇 2025-03-10 16:57

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/63509.html