现在的位置: 首页 > 综合 > 正文

基于memcached的SNA实现(2)

2014年03月12日 ⁄ 综合 ⁄ 共 4519字 ⁄ 字号 评论关闭

二、 Session失效的处理
采用memcached作为httpsession的存储,并不直接保存httpsession对象,自定义SessionMap,SessionMap直接继承HashMap,保存SessionMap。

会话胶粘:未失败转发的情况下没必要在memcached保存的SessionMap和httpsession之间复制来复制去,眉来眼去。

利用memcached计数器保存在线人数。

系统权限采用了acegi,在acegi的拦截器链里配置snaFilter

<bean id="filterChainProxy"
           class
="org.acegisecurity.util.FilterChainProxy">
        
<property name="filterInvocationDefinitionSource">
            
<value>
                 CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
                 PATTERN_TYPE_APACHE_ANT
                
/**=snaFilter,httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,basicProcessingFilter,securityContextHolderAwareRequestFilter,exceptionTranslationFilter,filterInvocationInterceptor
            
</value>
        
</property>
</bean>

注意需要配置在第一个。
snaFilter的职责:
1、 没有HttpSession时,创建HttpSession;
2、 创建Cookie保存HttpSession id;
3、 如果Cookie保存的HttpSession id与当前HttpSession id一致,说明是正常请求;
4、 如果Cookie保存的HttpSession id与当前HttpSession id不一致,说明是失败转发;失败转发的处理:
     4.1、根据Cookie保存的HttpSession id从memcached获取SessionMap;
     4.2、SessionMap属性复制到当前HttpSession;
     4.3、memcached删除SessionMap。
5、 判断当前请求url是否是登出url,是则删除SessionMap,在线人数减1.

代码:

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

利用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);
         }
     }

三、 文件保存的处理

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

抱歉!评论已关闭.