基于memcached的SNA实现

系统要集群,使用SNA方案。

一、缓存的处理

缓存要使用统一的缓存服务器,集中式缓存。

原先的实现采用ehcache。

在spring里的配置,以资源缓存为例:
/**
 


* User: ronghao
 


* Date: 2008-10-14
 


* Time: 10:36:30
 


* 管理Memcached 的CacheManager
 


*/
  



public
 
class
 MemcachedCacheManagerFactoryBean 
implements
 FactoryBean, InitializingBean, DisposableBean {  



  


    protected
 
final
 Log logger = LogFactory.getLog(getClass());  



  


    private
 ICacheManager<IMemcachedCache> cacheManager;  



  


    public
 Object getObject() 
throws
 Exception {  



        return
 cacheManager;  



    }  


  


    public
 Class getObjectType() {  



        return
 
this
.cacheManager.getClass();  



    }  


  


    public
 
boolean
 isSingleton() {  



        return
 
true
;  



    }  


  


    public
 
void
 afterPropertiesSet() 
throws
 Exception {  



        logger.info("Initializing Memcached CacheManager"
);  



        cacheManager = CacheUtil.getCacheManager(IMemcachedCache.class
,  



                MemcachedCacheManager.class
.getName());  



        cacheManager.start();  


    }  


  


    public
 
void
 destroy() 
throws
 Exception {  



        logger.info("Shutting down Memcached CacheManager"
);  



        cacheManager.stop();  


    }  


}  
/**
* User: ronghao
* Date: 2008-10-14
* Time: 10:36:30
* 管理Memcached 的CacheManager
*/
public class MemcachedCacheManagerFactoryBean implements FactoryBean, InitializingBean, DisposableBean {

    protected final Log logger = LogFactory.getLog(getClass());

    private ICacheManager<IMemcachedCache> cacheManager;

    public Object getObject() throws Exception {
        return cacheManager;
    }

    public Class getObjectType() {
        return this.cacheManager.getClass();
    }

    public boolean isSingleton() {
        return true;
    }

    public void afterPropertiesSet() throws Exception {
        logger.info("Initializing Memcached CacheManager");
        cacheManager = CacheUtil.getCacheManager(IMemcachedCache.class,
                MemcachedCacheManager.class.getName());
        cacheManager.start();
    }

    public void destroy() throws Exception {
        logger.info("Shutting down Memcached CacheManager");
        cacheManager.stop();
    }
}
 

配置:

/**
 


* User: ronghao
 


* Date: 2008-10-14
 


* Time: 10:37:16
 


* 返回  MemcachedCache
 


*/
  



public
 
class
 MemcachedCacheFactoryBean 
implements
 FactoryBean, BeanNameAware, InitializingBean {  



  


    protected
 
final
 Log logger = LogFactory.getLog(getClass());  



  


    private
 ICacheManager<IMemcachedCache> cacheManager;  



    private
 String cacheName;  



    private
 String beanName;  



    private
 IMemcachedCache cache;  



  


    public
 
void
 setCacheManager(ICacheManager<IMemcachedCache> cacheManager) {  



        this
.cacheManager = cacheManager;  



    }  


  


    public
 
void
 setCacheName(String cacheName) {  



        this
.cacheName = cacheName;  



    }  


  


    public
 Object getObject() 
throws
 Exception {  



        return
 cache;  



    }  


  


    public
 Class getObjectType() {  



        return
 
this
.cache.getClass();  



    }  


  


    public
 
boolean
 isSingleton() {  



        return
 
true
;   



    }  


  


    public
 
void
 setBeanName(String name) {  



        this
.beanName=name;  



    }  


  


    public
 
void
 afterPropertiesSet() 
throws
 Exception {  



        // If no cache name given, use bean name as cache name.
  



       if
 (
this
.cacheName == 
null
) {  



        this
.cacheName = 
this
.beanName;  



    }  


        cache = cacheManager.getCache(cacheName);  


    }  


}  
/**
* User: ronghao
* Date: 2008-10-14
* Time: 10:37:16
* 返回  MemcachedCache
*/
public class MemcachedCacheFactoryBean implements FactoryBean, BeanNameAware, InitializingBean {

    protected final Log logger = LogFactory.getLog(getClass());

    private ICacheManager<IMemcachedCache> cacheManager;
    private String cacheName;
    private String beanName;
    private IMemcachedCache cache;

    public void setCacheManager(ICacheManager<IMemcachedCache> cacheManager) {
        this.cacheManager = cacheManager;
    }

    public void setCacheName(String cacheName) {
        this.cacheName = cacheName;
    }

    public Object getObject() throws Exception {
        return cache;
    }

    public Class getObjectType() {
        return this.cache.getClass();
    }

    public boolean isSingleton() {
        return true; 
    }

    public void setBeanName(String name) {
        this.beanName=name;
    }

    public void afterPropertiesSet() throws Exception {
        // If no cache name given, use bean name as cache name.
       if (this.cacheName == null) {
		this.cacheName = this.beanName;
	}
        cache = cacheManager.getCache(cacheName);
    }
}
 

配置:

public
 
void
 doFilter(ServletRequest servletRequest, ServletResponse servletResponse,  



                         FilterChain filterChain) throws
 IOException, ServletException {  



        final
 HttpServletRequest hrequest = (HttpServletRequest) servletRequest;  



        final
 HttpServletResponse hresponse = (HttpServletResponse) servletResponse;  



        String uri = hrequest.getRequestURI();  


        logger.debug("开始SNA拦截-----------------"
 + uri);  



        HttpSession httpSession = hrequest.getSession();  


        String sessionId = httpSession.getId();  


        //如果是登出,则直接干掉sessionMap
  



        if
 (uri.equals(logoutUrl)) {  



            logger.debug("remove sessionmap:"
 + sessionId);  



            //在线人数减1
  



            getCache().addOrDecr("userCount"
,
1
);  



            getCache().remove(sessionId);  


        } else
 {  



            String cookiesessionid = getSessionIdFromCookie(hrequest, hresponse);  


            if
 (!sessionId.equals(cookiesessionid)) {  



                createCookie(sessionId, hresponse);  


                SessionMap sessionMap = getSessionMap(cookiesessionid);  


                if
 (sessionMap != 
null
) {  



                    logger.debug("fail over--------sessionid:"
 + sessionId + 
"cookiesessionid:"
 + cookiesessionid);  



                    initialHttpSession(sessionMap, httpSession);  


                    cache.remove(cookiesessionid);  


                }  


            }  


        }  


        filterChain.doFilter(hrequest, hresponse);  


}  
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
                         FilterChain filterChain) throws IOException, ServletException {
        final HttpServletRequest hrequest = (HttpServletRequest) servletRequest;
        final HttpServletResponse hresponse = (HttpServletResponse) servletResponse;
        String uri = hrequest.getRequestURI();
        logger.debug("开始SNA拦截-----------------" + uri);
        HttpSession httpSession = hrequest.getSession();
        String sessionId = httpSession.getId();
        //如果是登出,则直接干掉sessionMap
        if (uri.equals(logoutUrl)) {
            logger.debug("remove sessionmap:" + sessionId);
            //在线人数减1
            getCache().addOrDecr("userCount",1);
            getCache().remove(sessionId);
        } else {
            String cookiesessionid = getSessionIdFromCookie(hrequest, hresponse);
            if (!sessionId.equals(cookiesessionid)) {
                createCookie(sessionId, hresponse);
                SessionMap sessionMap = getSessionMap(cookiesessionid);
                if (sessionMap != null) {
                    logger.debug("fail over--------sessionid:" + sessionId + "cookiesessionid:" + cookiesessionid);
                    initialHttpSession(sessionMap, httpSession);
                    cache.remove(cookiesessionid);
                }
            }
        }
        filterChain.doFilter(hrequest, hresponse);
}
 

利用HttpSessionAttributeListener监听httpsession的属性变化,同步到memecached中的sessionmap。

public
 
void
 attributeAdded(HttpSessionBindingEvent event) {  



        HttpSession httpSession = event.getSession();  


        String attrName = event.getName();  


        Object attrValue = event.getValue();  


        String sessionId = httpSession.getId();  


        logger.debug("attributeAdded sessionId:"
 + sessionId + 
"name:"
 + attrName + 
",value:"
 + attrValue);  



        SessionMap sessionMap = getSessionMap(sessionId);  


        if
 (sessionMap == 
null
){  



            //在线人数加1
  



            getCache().addOrIncr("userCount"
,
1
);  



            sessionMap = new
 SessionMap();  



        }  


        logger.debug("name:"
 + attrName + 
",value:"
 + attrValue);  



        sessionMap.put(attrName, attrValue);  


        getCache().put(sessionId, sessionMap);  


    }  


  


    public
 
void
 attributeRemoved(HttpSessionBindingEvent event) {  



        HttpSession httpSession = event.getSession();  


        String attrName = event.getName();  


        String sessionId = httpSession.getId();  


        logger.debug("attributeRemoved sessionId:"
 + sessionId + 
"name:"
 + attrName);  



        SessionMap sessionMap = getSessionMap(sessionId);  


        if
 (sessionMap != 
null
) {  



            logger.debug("remove:"
 + attrName);  



            sessionMap.remove(attrName);  


            getCache().put(sessionId, sessionMap);  


        }  


    }  


  


    public
 
void
 attributeReplaced(HttpSessionBindingEvent event) {  



        attributeAdded(event);  


    }  
public void attributeAdded(HttpSessionBindingEvent event) {
        HttpSession httpSession = event.getSession();
        String attrName = event.getName();
        Object attrValue = event.getValue();
        String sessionId = httpSession.getId();
        logger.debug("attributeAdded sessionId:" + sessionId + "name:" + attrName + ",value:" + attrValue);
        SessionMap sessionMap = getSessionMap(sessionId);
        if (sessionMap == null){
            //在线人数加1
            getCache().addOrIncr("userCount",1);
            sessionMap = new SessionMap();
        }
        logger.debug("name:" + attrName + ",value:" + attrValue);
        sessionMap.put(attrName, attrValue);
        getCache().put(sessionId, sessionMap);
    }

    public void attributeRemoved(HttpSessionBindingEvent event) {
        HttpSession httpSession = event.getSession();
        String attrName = event.getName();
        String sessionId = httpSession.getId();
        logger.debug("attributeRemoved sessionId:" + sessionId + "name:" + attrName);
        SessionMap sessionMap = getSessionMap(sessionId);
        if (sessionMap != null) {
            logger.debug("remove:" + attrName);
            sessionMap.remove(attrName);
            getCache().put(sessionId, sessionMap);
        }
    }

    public void attributeReplaced(HttpSessionBindingEvent event) {
        attributeAdded(event);
    }
 

利用HttpSessionListener,sessionDestroyed事件时根据sessionid删除memcached里的sessionMap(如果存在)。不再担心httpsession的过期问题。

public
 
void
 sessionDestroyed(HttpSessionEvent event) {  



        HttpSession httpSession = event.getSession();  


        String sessionId = httpSession.getId();  


        logger.debug("session Removed sessionId:"
 + sessionId);  



        SessionMap sessionMap = getSessionMap(sessionId);  


        if
 (sessionMap != 
null
) {  



            logger.debug("remove sessionmap:"
 + sessionId);  



            //在线人数减1
  



            getCache().addOrDecr("userCount"
,
1
);  



            getCache().remove(sessionId);  


        }  


    }  
public void sessionDestroyed(HttpSessionEvent event) {
        HttpSession httpSession = event.getSession();
        String sessionId = httpSession.getId();
        logger.debug("session Removed sessionId:" + sessionId);
        SessionMap sessionMap = getSessionMap(sessionId);
        if (sessionMap != null) {
            logger.debug("remove sessionmap:" + sessionId);
            //在线人数减1
            getCache().addOrDecr("userCount",1);
            getCache().remove(sessionId);
        }
    }
 

三、文件保存的处理

和缓存类似,采用集中式的文件服务。对于linux,采用nfs。参考文档http://linux.vbird.org/linux_server/0330nfs.php#What_NFS_perm。关键在于对权限的分配。

应用程序本身不用修改。

相关推荐