分布式Session的一个实现.

阅读更多

本来一个Tomcat集群4台服务器工作的很好,随着访问量的增加本来的粘性Session方式的配置没办法很好的一碗水端平了.Session复制的话对于网络又是一个负担,所以才自己实现了一套利用Memcache的Session实现. 

网上已经有很多这样的实现了,比如修改Tomcat的Manager的http://code.google.com/p/memcached-session-manager/. 

但由于我这里还有其他的Servlet容器,所以也就没有使用完全自己实现了一套,现在运行在www.etnet.com.cn网站上. 

从那开始呢....其他的Servlet容器我总不能再一一去实现吧。。。。最后还是决定使用过滤器来偷梁换柱了. 

先是  CacheSessionFilter ,这个过滤器负责将普通的HttpServletRequest替换成我们自己的实现. 

Java代码    收藏代码
  1. public class CacheSessionFilter extends BaseFilter {  
  2.   
  3.     **  
  4.      * 替换原始的Request,修改为  
  5.      * com.etnetchina.servlet.wrapper.CacheSessionHttpServletReqeust。  
  6.      * 并根据是否新生成了Session来更新客户端的cookie.  
  7.      *   
  8.      * @param request 请求。  
  9.      * @param response 响应。  
  10.      * @param chain 下一个过滤器。  
  11.      * @throws java.io.IOException  
  12.      * @throws javax.servlet.ServletException  
  13.      */  
  14.     public void doFilter(  
  15.             ServletRequest request,  
  16.             ServletResponse response,  
  17.             FilterChain chain)  
  18.             throws IOException, ServletException {  
  19.         logger.debugLog("CacheSessionFilter to work.");  
  20.   
  21.         HttpServletRequest httpRequest = (HttpServletRequest) request;  
  22.         HttpServletResponse httpResponse = (HttpServletResponse) response;  
  23.   
  24.         CacheSessionHttpServletReqeust cacheRequest =  
  25.                 new CacheSessionHttpServletReqeust(  
  26.                 httpRequest,  
  27.                 httpResponse,  
  28.                 filterConfig.getServletContext());  
  29.         cacheRequest.setSessionCookieName(sessionCookieName);  
  30.         cacheRequest.setMaxInactiveInterval(maxInactiveInterval);  
  31.         cacheRequest.setCookieDomain(cookieDomain);  
  32.         cacheRequest.setCookieContextPath(cookieContextPath);  
  33.         cacheRequest.setSessionAttributeListeners(sessionAttributeListeners);  
  34.         cacheRequest.setSessionListeners(sessionListeners);  
  35.   
  36.         chain.doFilter(cacheRequest, httpResponse);  
  37.   
  38.         CacheHttpSession cacheSession = cacheRequest.currentSession();  
  39.         if (cacheSession != null) {  
  40.             if (!cacheSession.synchronizationCache()) {  
  41.                 WebUtil.failureCookie(  
  42.                         httpRequest,  
  43.                         httpResponse,  
  44.                         sessionCookieName,  
  45.                         cookieDomain,  
  46.                         cookieContextPath);  
  47.             }  
  48.         }  
  49.     }  
  50. }  



这个过滤器的核心就是doFilter方法了,做了三件事. 
第一是替换HttpServletRequest. 
第二是如果Session失效,负责删除Cookie中的SessionId. 
最后一件就是如果Session中的数据被改变了同步到缓存中. 

现在重点是我们换上的CacheHttpServletRequest有什么用呢,很简单只是在应用调用getSession()方法时返回我们实现的Session.其核心的代码很简单,如下. 

Java代码    收藏代码
  1. private HttpSession doGetSession(boolean create) {  
  2.         if (cacheSession != null) {  
  3.             //local,return.  
  4.             logger.debugLog("Session[{0}] was existed.", cacheSession.getId());  
  5.         } else {  
  6.             Cookie cookie = WebUtil.findCookie(this, getSessionCookieName());  
  7.             if (cookie != null) {  
  8.   
  9.                 logger.debugLog("Find session`s id from cookie.[{0}]",  
  10.                         cookie.getValue());  
  11.   
  12.                 cacheSession = buildCacheHttpSession(cookie.getValue(), false);  
  13.             } else {  
  14.                 cacheSession = buildCacheHttpSession(create);  
  15.             }  
  16.         }  
  17.   
  18.         if (cacheSession != null) {  
  19.             //dead?  
  20.             if (cacheSession.isInvalid()) {  
  21.                 cacheSession.invalidate();  
  22.                 cacheSession.synchronizationCache();  
  23.                 cacheSession = buildCacheHttpSession(create);  
  24.             }  
  25.   
  26.             if (cacheSession != null) {  
  27.                 cacheSession.access();  
  28.             }  
  29.         }  
  30.   
  31.         return cacheSession;  
  32. }  



getSession()和getSession(boolean)方法实际调用的就是这个方法,为了减少创建的损耗在一次请求中利保只会创建一次.最后更新一下这个Session的最后访问时间. 

每一次请求结束,都会进行一次缓存同步.由于每次讲求都会造成访问时间的更新,所以这个值是一直会被put到缓存中的. 

启用只需要在web.xml做如下配置. 

Xml代码    收藏代码
  1. <filter>  
  2.         <description>修改默认的Session储存机制,改为使用某个缓存来储存。description>  
  3.         <filter-name>CacheSessionFilterfilter-name>  
  4.         <filter-class>com.etnetchina.servlet.filter.session.CacheSessionFilterfilter-class>  
  5.         <init-param>  
  6.             <description>sessionId在Cookie中的名称description>  
  7.             <param-name>sessionCookieNameparam-name>  
  8.             <param-value>etnetsessionidparam-value>  
  9.         init-param>  
  10.         <init-param>  
  11.             <description>Session的最大不活动时间(秒)description>  
  12.             <param-name>maxInactiveIntervalparam-name>  
  13.             <param-value>60param-value>  
  14.         init-param>  
  15.     filter>  



还可以有以下参数可配置 
cookieDomain为存放cookie的域设置。默认为null. 
cookieContextPath为存放cookie的路径。如果不设置将使用默认的contextPath. 
sessionAttributeListeners 为HttpSessionAttributeListener监听器实现类全限定名,多个名称以","分隔. 
sessionListeners 为HttpSessionListener监听器实现类的全限定名,多个名称以","分隔. 

Xml代码    收藏代码
  1. <filter-mapping>  
  2.         <filter-name>CacheSessionFilterfilter-name>  
  3.         <url-pattern>/*url-pattern>  
  4. filter-mapping>  


加上一个过滤器就行了. 

 

 

其他分布式缓存实现方法

https://code.google.com/p/memcached-session-filter/

你可能感兴趣的:(分布式缓存)