基於Redis實現分布式Session

來源:互聯網
上載者:User

基於Redis實現分布式Session

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
// 建立Session
int maxIdleSeconds = 60 * 20 ;
ApiSession session = new ApiSession( maxIdleSeconds );
String sessId = session.getId();
session.setAttribute("CURRENT_USER", user);1
3.2、讀取Session
// 讀取Session
ApiSession 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中取出token
String token = (String)session.getAttribute(Const.TOKEN_SESSION_KEY);
if(StringUtils.isEmpty(token)){
    return false;
}
// 同調用方提交的比較
if(token.equalsIgnoreCase(tokenToBeChecked)){
    session.refresh();
    return true;
}

4、最佳化點
以上只是提供了實現範例。進一步的最佳化點包括:

Redis儲存規劃,設計Session Id 、Attr的儲存方式。
採用自己的持久化方式,提高持久化效率。
提供更多工具方法,讓Session更易用。
進一步實現Session的其他介面。
等等。

未盡事宜,歡迎留言討論。

Ubuntu 14.04下Redis安裝及簡單測試

Redis叢集明細文檔

Ubuntu 12.10下安裝Redis(圖文詳解)+ Jedis串連Redis

Redis系列-安裝部署維護篇

CentOS 6.3安裝Redis

Redis安裝部署學習筆記

Redis設定檔redis.conf 詳解

Redis 的詳細介紹:請點這裡
Redis 的:請點這裡

本文永久更新連結地址:

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.