Memcache存儲session,修改tomcat源碼,實現全站二級域名session共享

上篇文章中的方案,在外部顯式的使用memcache來替代session,雖然能夠達到各個服務器session共享的目的,可是改變了開發人員獲取session的方式。java

本篇介紹的方法能夠在不重構原來代碼,不改變代碼習慣的狀況下,實現session共享的目的。web

兩種方法各有利弊,第一種方法編碼方式改變比較大,開發人員可能不習慣,可是不受服務器類型的影響;第二種方法,針對tomcat服務器,須要修改tomcat源碼,可是不須要重構代碼,代碼中對session的操做還和之前同樣。apache

第二種方式主要作兩處改動:tomcat

1,使用memcache來覆蓋tomcat對session的實現。將session存入memcache中。服務器

package org.apache.catalina.session;import java.io.*;import com.danga.MemCached.*;import org.apache.catalina.*;public class MemcachedManager extends StandardManager {
    protected MemCachedClient mc = null;
    protected SockIOPool pool = null;
    protected String sockPoolName = "snasessionsock";
    protected String serverlist = "192.168.2.194:12000";
    protected String snaidPerfix = "snaid";
    protected String snaidFlag = "true";
    public MemcachedManager() {
        super();
    }

    public Session findSession(String id) throws IOException {
        Session session = super.findSession(id);
        if (session == null && id != null) {
            try {
                Object sid = mc.get(this.getSnaidPerfix() + id);
                if (sid != null) {
                    session = createSession(id);
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        return session;
    }

    public Session createSession(String sessionId) {
        Session session = super.createSession(sessionId);
        mc.set(this.getSnaidPerfix() + session.getId(), snaidFlag);
        return session;
    }

    protected StandardSession getNewSession() {
        return new MemcachedSession(this, mc);
    }

    protected void initPool() {
        try {
            if (pool == null) {
                try {
                    pool = SockIOPool.getInstance();
                    pool.setServers(serverlist.split(","));
                    pool.setInitConn(5);
                    pool.setMinConn(5);
                    pool.setMaxConn(50);
                    pool.setMaintSleep(30);
                    pool.setNagle(false);
                    pool.initialize();
                } catch (Exception ex) {// log.error("error:", ex);                 }
            }
        } catch (Exception ex) {// log.error("error:", ex);         }

        if (mc == null) {
            mc = new MemCachedClient();// mc.setPoolName(sockPoolName);             mc.setCompressEnable(false);
            mc.setCompressThreshold(0);
        }
    }

    protected void closePool() {
        if (mc != null) {
            try {
            } catch (Exception ex) {// log.error("error:", ex);             }
            mc = null;
        }
        if (pool != null) {
            try {
                pool.shutDown();
            } catch (Exception ex) {// log.error("error:", ex);             }
        }
    }

    public String getSockPoolName() {
        return sockPoolName;
    }

    public String getServerlist() {
        return serverlist;
    }

    public String getSnaidPerfix() {
        return snaidPerfix;
    }

    public String getSnaidFlag() {
        return snaidFlag;
    }

    public void setSockPoolName(String sockPoolName) {
        this.sockPoolName = sockPoolName;
    }

    public void setServerlist(String serverlist) {
        this.serverlist = serverlist;
    }

    public void setSnaidPerfix(String snaidPerfix) {
        this.snaidPerfix = snaidPerfix;
    }

    public void setSnaidFlag(String snaidFlag) {
        this.snaidFlag = snaidFlag;
    }

    protected String generateSessionId() {
        if (this.getJvmRoute() != null) {
            return java.util.UUID.randomUUID().toString() + '.' +
                    this.getJvmRoute();
        }
        return java.util.UUID.randomUUID().toString();
    }

    public void start() throws LifecycleException {
        this.setPathname(""); // must disable session persistence across Tomcat restarts         super.start();
        this.initPool();
    }

    public void stop() throws LifecycleException {
        super.stop();
        this.closePool();
    }
}

---------------------------------------------------------------------------------------------------cookie

package org.apache.catalina.session;import com.danga.MemCached.*;import org.apache.catalina.*;public class MemcachedSession extends StandardSession {
    protected transient MemCachedClient mc = null;
    public MemcachedSession(Manager manager,
                            MemCachedClient mc) {
        super(manager);
        this.mc = mc;
    }


    public Object getAttribute(String name) {
        Object obj = super.getAttribute(name);
        if (obj != null && !(obj instanceof java.io.Serializable)) {
            return obj;
        }
        String key = name + this.getId();
        obj = mc.get(key);
        return obj;
    }

    public void setAttribute(String name, Object value) {
        removeAttribute(name);
        super.setAttribute(name, value);
        if (value != null && value instanceof java.io.Serializable) {
            String key = name + this.getId();
            mc.set(key, value);
        }
    }

    protected void removeAttributeInternal(String name, boolean notify) {
        super.removeAttributeInternal(name, notify);
        String key = name + this.getId();
        mc.delete(key);
    }

    public void expire(boolean notify) {
        mc.delete(((MemcachedManager) manager).getSnaidPerfix() + this.getId());
        super.expire(notify);
    }

}

(能夠使用本身項目中memcache的操做類來替代上面兩個類的memcache操做)session

將兩個類打jar包,置於tomcat/lib下dom

修改tomcat/conf/context.xml文件,內容以下:this

<?xml version='1.0' encoding='utf-8'?>
<Context>
	<Loader delegate="true"/> <!--這句話須要添加,不加可能報錯-->
    <!-- Default set of monitored resources -->
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
 <Manager className="org.apache.catalina.session.MemcachedManager" serverlist="192.168.2.194:12000" snaidPerfix="snaid" snaidFlag="true">
</Manager>	
</Context>

通過以上的修改,tomcat對session的操做會自動使用org.apache.catalina.session.MemcachedManager 來替代。編碼

2,修改tomcat源碼,使tomcat在向客戶端setcookie的時候,設置cookie的做用域爲全站。這樣能夠全部的tomcat共用一個JSESSIONID。

下載tomcat的源碼。

修改org.apache.catalina.connector.Request.java

/** * Configures the given JSESSIONID cookie. * * @param cookie The JSESSIONID cookie to be configured */     protected void configureSessionCookie(Cookie cookie) {
        cookie.setMaxAge(-1);
        String contextPath = null;
        if (!connector.getEmptySessionPath() && (getContext() != null)) {
            contextPath = getContext().getEncodedPath();
        }
        if ((contextPath != null) && (contextPath.length() > 0)) {
            cookie.setPath(contextPath);
        } else {
            cookie.setPath("/");
        }
        //added by sufeng,make tomcat jsessionid cross docin.com         if (null != System.getProperty("sessionShareDomain") && !"".equals(System.getProperty("sessionShareDomain")))
            cookie.setDomain(System.getProperty("sessionShareDomain"));
        //added by sufeng end         if (isSecure()) {
            cookie.setSecure(true);
        }
    }
  1. 修改配置:tomcat\conf\catalina.properties,在最後添加一行

    sessionShareDomain=sufeng.com

  2. session
  3. 從新訪問,會發現,JSEESIONID的做用域變成了sufeng.com,這樣在兩個子域的tomcat服務器能夠共享同一個sessionid,並經過相同的sessionid到memcache中取session數據。不對tomcat源碼進行修改,兩個二級域的tomcat將分別生成不一樣的JSESSION值,而且做用域是本身的二級域名。即圖中上面的兩個cookie。
  4. 參考:
  5. http://www.javayou.com/diary/8534
  6. http://www.javaeye.com/topic/81641
  7. http://soyul.javaeye.com/blog/445838
  8. http://apache.freelamp.com/tomcat/tomcat-6/v6.0.20/src/apache-tomcat-6.0.20-src.zip
相關文章
相關標籤/搜索