apache shiro框架如何使用nginx负载

来源:互联网 发布:linx mysql执行sql文件 编辑:程序博客网 时间:2024/05/16 03:41

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 */@Componentpublic 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共享的问题。