qaqa12345667 发表于 2015-11-18 12:47:32

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

  上篇文章中的方案,在外部显式的使用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=&quot;true&quot;/> <!--这句话需要添加,不加可能报错-->
<!-- Default set of monitored resources -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<Manager className=&quot;org.apache.catalina.session.MemcachedManager&quot; serverlist=&quot;192.168.2.194:12000&quot; snaidPerfix=&quot;snaid&quot; snaidFlag=&quot;true&quot;>
</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(&quot;/&quot;);
}
//added by sufeng,make tomcat jsessionid cross docin.com
if (null != System.getProperty(&quot;sessionShareDomain&quot;) && !&quot;&quot;.equals(System.getProperty(&quot;sessionShareDomain&quot;)))
cookie.setDomain(System.getProperty(&quot;sessionShareDomain&quot;));
//added by sufeng end
if (isSecure()) {
cookie.setSecure(true);
}
}

[*]在tomcat/conf/catalina.properties 中添加
[*]sessionShareDomain=sufeng.com
[*]

[*]
[*]重新访问,会发现,JSEESIONID的作用域变成了sufeng.com,这样在两个子域的tomcat服务器可以共享同一个sessionid,并通过相同的sessionid到memcache中取session数据。不对tomcat源码进行修改,两个二级域的tomcat将分别生成不同的JSESSION值,并且作用域是自己的二级域名。即图中上面的两个cookie。
[*]

[*]参考:
[*]http://www.javayou.com/diary/8534
[*]http://www.javaeye.com/topic/81641
[*]http://soyul.javaeye.com/blog/445838
[*]http://apache.freelamp.com/tomcat/tomcat-6/v6.0.20/src/apache-tomcat-6.0.20-src.zip  


   
版权声明:本文为博主原创文章,未经博主允许不得转载。
页: [1]
查看完整版本: Memcache存储session,修改tomcat源码,实现全站二级域名session共享