一、环境
- redis集群,客户端使用JedisCluster
- shiro + ssm项目
二、代码
1. 继承AbstractSessionDAO,实现相关方法,可以参照其他的实现去写,如:MemorySessionDAO
package com.sunline.webins.shiro;
import com.sunline.j2cache.util.SerializationUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;
import java.io.IOException;
import java.io.Serializable;
import java.util.*;
public class RedisSessionDao extends AbstractSessionDAO {
private JedisCluster jedisCluster;
private final int EXPIRE_TIME = 60*60;
private final String SHIRO_SESSION_PRI = "usersession:";
public JedisCluster getJedisCluster() {
return jedisCluster;
}
public void setJedisCluster(JedisCluster jedisCluster) {
this.jedisCluster = jedisCluster;
}
@Override
protected Serializable doCreate(Session session) {
Serializable sessionId = this.generateSessionId(session);
this.assignSessionId(session, sessionId);
byte[] bKes = (SHIRO_SESSION_PRI + sessionId).getBytes();
try {
byte [] bValue = SerializationUtils.serialize (session);
jedisCluster.set(bKes, bValue);
jedisCluster.expire(bKes, EXPIRE_TIME);
} catch (IOException e) {
e.printStackTrace();
}
return sessionId;
}
@Override
protected Session doReadSession(Serializable sessionId) {
if (sessionId == null) {
throw new NullPointerException("id argument cannot be null.");
}
Session session = null;
byte []bKes = (SHIRO_SESSION_PRI + sessionId).getBytes();
byte []resultBytes = jedisCluster.get(bKes);
try {
session = (Session) SerializationUtils.deserialize (resultBytes);
} catch (IOException e) {
e.printStackTrace();
}
return session;
}
@Override
public void update(Session session) throws UnknownSessionException {
String sessionId = (String) session.getId();
if (sessionId == null) {
throw new NullPointerException("id argument cannot be null.");
}
byte[] bKes = (SHIRO_SESSION_PRI + sessionId).getBytes();
try {
byte [] bValue = SerializationUtils.serialize (session);
jedisCluster.set(bKes, bValue);
jedisCluster.expire(bKes, EXPIRE_TIME);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void delete(Session session) {
if (session == null) {
throw new NullPointerException("session argument cannot be null.");
} else {
String sessionId = (String) session.getId();
if (sessionId != null) {
byte[] bKes = (SHIRO_SESSION_PRI + sessionId).getBytes();
jedisCluster.del(bKes);
}
}
}
@Override
public Collection<Session> getActiveSessions() {
Set<Session> sessionSet = new HashSet<>();
Map<String, JedisPool> clusterNodes = jedisCluster.getClusterNodes();
for (String s : clusterNodes.keySet()) {
JedisPool jedisPool = clusterNodes.get(s);
Set<byte[]> keys = jedisPool.getResource().keys((SHIRO_SESSION_PRI + "*").getBytes());
for (byte[] k : keys) {
byte[] bytes = jedisPool.getResource().get(k);
try {
Session session = (Session) SerializationUtils.deserialize (bytes);
sessionSet.add(session);
} catch (Exception e) {
e.printStackTrace();
}
}
}
return sessionSet;
}
}
2. 一次请求会多次调用doReadSession,给redis造成很大压力,因此做如下改造,减小redis的压力
package com.sunline.webins.shiro;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SessionKey;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.session.mgt.WebSessionKey;
import javax.servlet.ServletRequest;
import java.io.Serializable;
public class RedisWebSessionManager extends DefaultWebSessionManager {
@Override
protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException {
Serializable sessionId = this.getSessionId(sessionKey);
if (sessionId == null) {
return null;
} else {
WebSessionKey webSessionKey = (WebSessionKey) sessionKey;
ServletRequest servletRequest = webSessionKey.getServletRequest();
Session session = (Session) servletRequest.getAttribute(sessionId + "");
if (session != null) {
return session;
}
session = this.retrieveSessionFromDataSource(sessionId);
if (session == null) {
String msg = "Could not find session with ID [" + sessionId + "]";
throw new UnknownSessionException(msg);
} else {
servletRequest.setAttribute(sessionId + "", session);
return session;
}
}
}
}
3. 修改配置文件进行注入,这里只是我修改的部分,不是全部配置
<bean id="sessionDAO" class="com.sunline.webins.shiro.RedisSessionDao">
<property name="jedisCluster" ref="jedisCluster"></property>
</bean>
<bean id="sessionManager" class="com.sunline.webins.shiro.RedisWebSessionManager">
<!-- 注入sessionDAO -->
<property name="sessionDAO" ref="sessionDAO"></property>
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="authenticationRealm" />
<property name="cacheManager" ref="shiroCacheManager" />
<!-- DefaultWebSessionManager 改为 RedisWebSessionManager -->
<property name="sessionManager" ref="sessionManager"></property>
</bean>