上一章节我和大家分享的是如何扩展异步请求分支处理,这一章节我准备分享如何实现集中式session管理,shiro一大特色就是有自己一套session机制,与原生的httpsession差不多风格的api,用起来比较顺手,我个人也比较喜欢;spring security是比较依赖与原生httpsession,所以比较难扩展这会话机制,但是我们shiro使用者就不用担心这个问题,请大家准备好鸡蛋壳,香蕉皮吧...
进入主题,我们先看看session管理器
<!-- 会话管理器 --> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <property name="sessionValidationSchedulerEnabled" value="false" /> <property name="sessionDAO" ref="sessionDAO" /> <property name="globalSessionTimeout" value="60000"/> </bean>
基本用到就三个参数sessionValidationSchedulerEnabled(扫描session线程,负责清理超时会话), sessionDao是进行会话读写的实现,globalSessionTimeout是会话存活时间(默认是30分钟)
其他参数可看源码配置,象session的cookie编号键之类的,有需要才去改
下面看看我们的读写会话实现类
public class MCSessionDAO extends AbstractSessionDAO { private final static Logger log = LoggerFactory.getLogger(MCSessionDAO.class); private MemcachedClient client; public MCSessionDAO(MemcachedClient client) { if (client == null) { throw new RuntimeException("必须存在memcached客户端实例"); } this.client = client; } @Override protected Serializable doCreate(Session session) { Serializable sessionId = generateSessionId(session); assignSessionId(session, sessionId); try { client.set(sessionId.toString(), (int) session.getTimeout() / 1000, session); } catch (Exception e) { log.error(e.getMessage()); } return sessionId; } @Override protected Session doReadSession(Serializable sessionId) { Session session = null; try { session = client.get(sessionId.toString()); } catch (Exception e) { log.error(e.getMessage()); } return session; } @Override public void delete(Session session) { try { client.delete(session.getId().toString()); } catch (Exception e) { log.error(e.getMessage()); } } @Override public Collection<Session> getActiveSessions() { return Collections.emptySet(); } @Override public void update(Session session) throws UnknownSessionException { try { client.replace(session.getId().toString(), (int) session.getTimeout() / 1000, session); } catch (Exception e) { log.error(e.getMessage()); } } }
getActiveSessions这个方法是用来统计当前活动的session,但是memcached也没有特别好的方法能获取同一批键值对,暂时只能不支持方法,如果有朋友想到好的解决方案,望请告知下小弟
其实这个类跟普通的crud差不多,主要是通过设置memcached的过期时间来作为session的存活时间,如果返回为null则认为session是登录超时了,值得注意一个问题memcached应该需要评估足够多的初始化内存,不然可能用户量一上去,就可能有会话丢失的可能,毕竟内存不够了memcached会自动把旧的一些数据挤出去,这要看memcached的失效策略设置
很明显我们这里的sessionDao实现类已经完成,然后配置到文件里面
<!-- 会话读写实现类 --> <bean id="sessionDAO" class="com.silvery.security.shiro.session.MCSessionDAO"> <constructor-arg ref="memcachedClient" /> </bean>
然后我们的会话管理器又要配置到哪里呢
<!-- 安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="sessionManager" ref="sessionManager" /> <property name="cacheManager" ref="shiroCacheManager" /> <property name="realm" ref="simpleUserRealm" /> </bean>
然后就完工了,最后就配置个nginx+2个tomcat集群下访问测试下即可
欢迎拍砖...