Memcache存储session,修改tomcat源码,实现全站二级域名session共享

来源:互联网 发布:mac yy进入频道失败 编辑:程序博客网 时间:2024/06/05 11:01

上篇文章中的方案,在外部显式的使用memcache来替代session,虽然可以达到各个服务器session共享的目的,但是改变了开发人员获取session的方式。

本篇介绍的方法可以在不重构原来代码,不改变代码习惯的情况下,实现session共享的目的。

两种方法各有利弊,第一种方法编码方式改变比较大,开发人员可能不习惯,但是不受服务器类型的影响;第二种方法,针对tomcat服务器,需要修改tomcat源码,但是不需要重构代码,代码中对session的操作还和以前一样。

第二种方式主要做两处改动:

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();    }}

---------------------------------------------------------------------------------------------------

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操作)

将两个类打jar包,置于tomcat/lib下

修改tomcat/conf/context.xml文件,内容如下:

<?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. 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