您的位置:首页 > 运维架构 > Nginx

apache shiro框架如何使用nginx负载

2017-07-21 15:26 513 查看

1.apache shiro框架在使用负载均衡的时候出现的问题

当我进入我的项目的首页的时候发现是无法登陆的,原因是因为服务器之间的session没有共享这也是Apache Shiro集群需要解决的问题。
  Apache Shiro集群要解决2个问题,一个是session的共享问题,一个是授权信息的cache共享问题,官网给的例子是Ehcache的实现。这里我们可以

通过集成redis来实现。

2.apache shiro集成redis。

这个比较简单。只需要引入相关的jar包,我项目里的redis是使用的哨兵模式。配置如下:



redis的安装可以参考我之前写的文章。

3.apache shiro集群解决session共享的问题。

我们可以看DefaultWebSessionManager的源码,发现其父类DefaultSessionManager中有sessionDAO属性,这个属性是真正实现了session储存的类,这个就是我们自己实现的redis session的储存类。

之前我在项目中使用的是EnterpriseCacheSessionDAO
<property name="sessionDAO">
<bean class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"/>

</property>

现在我们就要通过redis来实现了。



redisShiroSessionDAO:

/**
* Created by Maggie on 2017/7/14.
*/
public class RedisSessionDAO extends AbstractSessionDAO {

private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class);

private ShiroSessionRepository shiroSessionRepository;

public ShiroSessionRepository getShiroSessionRepository() {
return shiroSessionRepository;
}

public void setShiroSessionRepository(
ShiroSessionRepository shiroSessionRepository) {
this.shiroSessionRepository = shiroSessionRepository;
}

@Override
public void update(Session session) throws UnknownSessionException {
getShiroSessionRepository().saveSession(session);
}

@Override
public void delete(Session session) {
getShiroSessionRepository().deleteSession(session.getId());
}

//用来统计当前活动的session
@Override
public Collection<Session> getActiveSessions() {
return shiroSessionRepository.getAllSessions();
}

@Override
protected Serializable doCreate(Session session) {
Serializable sessionId = this.generateSessionId(session);
this.assignSessionId(session, sessionId);
getShiroSessionRepository().saveSession(session);
return sessionId;
}

@Override
protected Session doReadSession(Serializable sessionId) {
return getShiroSessionRepository().getSession(sessionId);
}


shiroSessionRepository:

/**
* Created by Maggie on 2017/7/17.
*/
public class JedisShiroSessionRepository implements ShiroSessionRepository{

private static Logger logger = LoggerFactory.getLogger(JedisShiroSessionRepository.class);

public static final String REDIS_SHIRO_SESSION = "shiro_redis_session:";

public static final String REDIS_SHIRO_ALL = "*shiro_redis_session:*";

public RedisManager getRedisManager() {
return redisManager;
}

public void setRedisManager(RedisManager redisManager) {
this.redisManager = redisManager;
}

private RedisManager redisManager;

@Override
public void saveSession(Session session) {
if(session == null || session.getId() == null){
logger.error("session or session id is null");
return;
}
session.setTimeout(redisManager.getExpire()* TimeEnum.SESSION_TIME_BASE.getCode());
getRedisManager().insertObject(this.buildRedisSessionKey(session.getId()), session, redisManager.getExpire());
}

@Override
public void deleteSession(Serializable sessionId) {
if (sessionId == null) {
throw new NullPointerException("session id is empty");
}
getRedisManager().deleteObject(this.buildRedisSessionKey(sessionId));
}

@Override
public Session getSession(Serializable sessionId) {
if (sessionId == null)
throw new NullPointerException("session id is empty");
Session session = null;
try {
session =SerializeUtil.deserialize(getRedisManager().queryObjectByKey(this.buildRedisSessionKey(sessionId)),Session.class);
} catch (Exception e) {
logger.error( "获取session异常,id:[%s]",sessionId);
}
return session;
}

@Override
public Collection<Session> getAllSessions() {
Collection<Session> sessions = new HashSet<>();;
try {
Set<byte[]> byteKeys = getRedisManager().keys(REDIS_SHIRO_ALL);
if (byteKeys != null && byteKeys.size() > 0) {
for (byte[] bs : byteKeys) {
Session obj =SerializeUtil.deserialize(getRedisManager().queryObjectByKey(bs),Session.class);
if(obj instanceof Session){
sessions.add(obj);
}
}
}
} catch (Exception e) {
logger.error(e.toString(),"获取全部session异常");
}

return sessions;
}

private String buildRedisSessionKey(Serializable sessionId) {
return REDIS_SHIRO_SESSION + sessionId;
}
}



RedisManager:

/**
* Redis管理
* Created by Mac Zhang on 14-11-06 上午10:45
*/
@Component
public class RedisManager {

protected org.slf4j.Logger log = LoggerFactory.getLogger(this.getClass());

@Autowired
private StringRedisTemplate redisTemplate;

/**
* 查询redis数据库
* @param key 查询关键字
* @return redis 返回对象 ecustjxjy
*/
public byte[] queryObjectByKey(final Object key) {
log.debug("queryObjectByKey request:{}", key);
Object session =redisTemplate.execute(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection connection) throws DataAccessException {
byte[] redisKey=null;
if(key instanceof String) {
redisKey = serialize(key);
}else {
redisKey=(byte[])key;
}
if (connection.exists(redisKey)) {
return connection.get(redisKey);
}
return null;
}
});
return (byte[])session;
}

public Set<byte[]> keys(final String key){
log.debug("queryObjectByKey request:{}", key);
Set<byte[]> value=redisTemplate.execute(new RedisCallback<Set<byte[]>>() {
@Override
public Set<byte[]> doInRedis(RedisConnection connection) throws DataAccessException {
byte[] redisKey = serialize(key);
Set<byte[]> value = connection.keys(redisKey);
return value;
}
});
return value;
}

/**
* 插入redis 数据库,设置有效期
* @param obj 保存对象
* @param key 关键字
* @param timeout 有效期(秒)
* @return 对象类型,泛型
*/
public boolean insertObject(final String key,final Object obj,final long timeout){
log.debug("insertObject request:key={},obj={}", key, obj.getClass());
if(key.contains("SessionUser")){
System.out.println(SerializeUtil.deserialize((byte [])obj));
}
boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
byte [] redisKey = serialize(key);
byte [] redisValue = serialize(obj);
connection.set(redisKey,redisValue);
if(timeout > 0){
redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
}
return true;
}
});
log.debug("insertObject response:{}", result);
return result;
}

/**
* 删除redis 保存对象
* @param key 查询关键字
* @return boolean
*/
public boolean deleteObject(final String key){
log.info("deleteObject request:key={}", key);
Long result = redisTemplate.execute(new RedisCallback<Long>() {
@Override
public Long doInRedis(RedisConnection connection) throws DataAccessException {
byte [] redisKey = seri
ac4c
alize(key);
return connection.del(redisKey);
}
});
log.debug("deleteObject response:{}",result);
return result > 0;
}

/**
* 解决缓存key时前缀的乱码(序列化key时使用redis序列化)
* @param key
* @return
*/
public byte [] serialize(final Object key){
if(key instanceof String){
return this.redisTemplate.getStringSerializer().serialize(key.toString());
}
return SerializeUtil.serialize(key);
}

public long getExpire(){
return TimeEnum.REDIS_EXPIRE_TIME.getCode();
}

public Session deserialize(byte[] var1){
return  SerializeUtil.deserialize(var1,Session.class);
}

}

通过上面的方式就可以实现session共享了,并且session由redis来保存。下一篇解决cache共享的问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: