apache shiro框架如何使用nginx负载

2 篇文章 0 订阅
2 篇文章 0 订阅

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 = serialize(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共享的问题。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值