基于Redis实现分布式Session

来源:互联网 发布:康辉旅游网站源码 编辑:程序博客网 时间:2024/05/16 23:34

1、概述

我们可以自己实现类似Session的机制,采用 Redis 等分布式缓存中间件来实现。

Redis是独立于应用服务器的,基于Redis实现的Session机制自动具备了分布式属性。

Redis可以很方便地做集群配置,则Session避免了单点故障。

2、实现

实现代码极其简单,如下所示。

/** * @author liuhailong2008#foxmail */public class ApiSession implements Serializable {    private static final long serialVersionUID = 1055965810150154404L;    /**Session ID*/    private final String              id;    /**Session创建时间*/    private long                creationTime;    /**Session最后一次访问时间*/    private long                lastAccessedTime;    /**Session的最大空闲时间间隔*/    private int                 maxInactiveInterval;    /**是否是新建Session*/    private boolean             newSession;    private static final String SESSION_KEY_PREFIX = "SESS_";    //private Set<String> attrNameSet = Collections.synchronizedSet(new HashSet<String>());    private final String sessionKey ;    /**     * 创建新的Session。     * @param maxIdleSeconds     */    public ApiSession(int maxIdleSeconds){        id = StringUtil.getUUID();        long now = System.currentTimeMillis();        creationTime = now;        lastAccessedTime = now;        this.maxInactiveInterval = maxIdleSeconds;        newSession = true;        //this.attrNameSet.clear();        sessionKey = SESSION_KEY_PREFIX + id;        CacheBlock cb = CacheManager.getBlock(Const.CACHE_BLOCK_INDEX);        CacheElement ce = new CacheElement(sessionKey,this);        ce.setTimeToIdleSeconds(this.getMaxInactiveInterval());        cb.put(ce);    }    /**     * 通过Session id获取已经存在的Session,如果没有,返回null。     * @return     */    public static ApiSession get(String id){        String sessionKey = SESSION_KEY_PREFIX + id;        CacheBlock cb = CacheManager.getBlock(Const.CACHE_BLOCK_INDEX);        ApiSession ret = (ApiSession) cb.get(sessionKey);        if(ret!=null){            ret.newSession = false;            ret.refresh();        }        return ret;    }    /**     * 更新 lastAccessedTime 。     */    public void refresh() {        this.lastAccessedTime = System.currentTimeMillis();        CacheBlock cb = CacheManager.getBlock(Const.CACHE_BLOCK_INDEX);        CacheElement ce = new CacheElement(sessionKey,this);        ce.setTimeToIdleSeconds(this.getMaxInactiveInterval());        cb.put(ce);    }    /**     * 是否超时过期。     *      * @param session     * @return     */    public boolean isExpired() {        CacheBlock cb = CacheManager.getBlock(Const.CACHE_BLOCK_INDEX);        ApiSession _this = (ApiSession) cb.get(this.sessionKey);        // 先查看缓存层面的超时控制        if(_this==null){            return false;        }        long now = System.currentTimeMillis();        long last = this.getLastAccessedTime();        long interal = now - last;        if(interal>this.getMaxInactiveInterval()){            this.invalidate();            return true;        }else{            return false;        }    }    /**     * 强制Session立即失效。     */    public synchronized void invalidate() {        CacheBlock cb = CacheManager.getBlock(Const.CACHE_BLOCK_INDEX);        cb.remove(this.sessionKey);    }    /**     * 移除属性。     *      * @param attrName     * @return     */    public synchronized Object removeAttribute(String attrName){        this.refresh();        String attrSessionKey = getAttrSessionKey(attrName);        CacheBlock cb = CacheManager.getBlock(Const.CACHE_BLOCK_INDEX);        Object ret = cb.remove(attrSessionKey);        return ret;    }    /**     * 设置属性。     * @param attrName     * @param attrValue     */    public synchronized void setAttribute(String attrName,Object attrValue){        this.refresh();        String attrSessionKey = getAttrSessionKey(attrName);        CacheBlock cb = CacheManager.getBlock(Const.CACHE_BLOCK_INDEX);        CacheElement ce = new CacheElement(attrSessionKey,attrValue);        ce.setTimeToIdleSeconds(this.getMaxInactiveInterval());        cb.put(ce);    }    /**     * 获取属性的值。     * @param attrName     * @return     */    public Object getAttribute(String attrName){        this.refresh();        String attrSessionKey = getAttrSessionKey(attrName);        CacheBlock cb = CacheManager.getBlock(Const.CACHE_BLOCK_INDEX);        Object retObject = cb.get(attrSessionKey);        return retObject;    }    private String getAttrSessionKey(String attrName){        String attrSessionKey = sessionKey + attrName;        return attrSessionKey;    }    public int getMaxInactiveInterval() {        if(maxInactiveInterval==-1){            maxInactiveInterval = 3600;        }        return maxInactiveInterval;    }    public void setMaxInactiveInterval(int maxInactiveInterval) {        this.maxInactiveInterval = maxInactiveInterval;    }    public String getId() {        return id;    }    public long getCreationTime() {        return creationTime;    }    public long getLastAccessedTime() {        return lastAccessedTime;    }    public boolean isNewSession() {        return newSession;    }}

3、用法

3.1、建立Session

// 建立Sessionint maxIdleSeconds = 60 * 20 ;ApiSession session = new ApiSession( maxIdleSeconds );String sessId = session.getId();session.setAttribute("CURRENT_USER", user);

3.2、读取Session

// 读取SessionApiSession session = ApiSession.get(tokenToBeChecked);if(session==null){    logger.debug(String.format("会话超时啦,token:%s。", tokenToBeChecked));    return false;}// 检查是否超时boolean isExpired = session.isExpired();if(isExpired){    logger.debug(String.format("会话超时啦,token:%s。", tokenToBeChecked));    return false;}// 从Sesion中取出tokenString token = (String)session.getAttribute(Const.TOKEN_SESSION_KEY);if(StringUtils.isEmpty(token)){    return false;}// 同调用方提交的比较if(token.equalsIgnoreCase(tokenToBeChecked)){    session.refresh();    return true;}

4、优化点

以上只是提供了实现范例。进一步的优化点包括:

  1. Redis存储规划,设计Session Id 、Attr的存储方式。
  2. 采用自己的持久化方式,提高持久化效率。
  3. 提供更多工具方法,让Session更易用。
  4. 进一步实现Session的其他接口。

等等。

未尽事宜,欢迎留言讨论。

0 1
原创粉丝点击