posts - 193,  comments - 520,  trackbacks - 0

          系統(tǒng)要集群,使用SNA方案。
          一、 緩存的處理
          緩存要使用統(tǒng)一的緩存服務(wù)器,集中式緩存。
          原先的實(shí)現(xiàn)采用ehcache。
          在spring里的配置,以資源緩存為例:

          <!-- EhCache Manager -->
              
          <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
                  
          <property name="configLocation">
                      
          <value>classpath:ehcache.xml</value>
                  
          </property>
          </bean>

          <bean id="resourceCacheBackend"
                    class
          ="org.springframework.cache.ehcache.EhCacheFactoryBean">
                  
          <property name="cacheManager" ref="cacheManager"/>
                  
          <property name="cacheName" value="resourceCache"/>
              
          </bean>

              
          <bean id="resourceCache"
                    class
          ="com.framework.extcomponent.security.authentication.services.acegi.cache.EhCacheBasedResourceCache"
                    autowire
          ="byName">
                  
          <property name="cache" ref="resourceCacheBackend"/>
              
          </bean>

          
          

          cacheManager負(fù)責(zé)對(duì)ehcache進(jìn)行管理,初始化、啟動(dòng)、停止。
          resourceCacheBackend負(fù)責(zé)實(shí)際執(zhí)行緩存操作,put 、get、remove。
          resourceCache實(shí)現(xiàn)具有業(yè)務(wù)語(yǔ)義的業(yè)務(wù)應(yīng)用層面的緩存操作,內(nèi)部調(diào)用resourceCacheBackend操作。

          現(xiàn)在采用memcached。
          關(guān)于客戶(hù)端,采用文初封裝的客戶(hù)端,地址在http://code.google.com/p/memcache-client-forjava/。
          使用spring的FactoryBean進(jìn)行二次封裝。同理:
          memcachedManager負(fù)責(zé)對(duì)memcached進(jìn)行管理,初始化、啟動(dòng)、停止。
          代碼:

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

          配置:


          <bean id="memcachedManager"
                    class
          ="com.framework.extcomponent.cache.MemcachedCacheManagerFactoryBean"/>
          
           
          

          resourceCacheBackend負(fù)責(zé)實(shí)際執(zhí)行緩存操作,put 、get、remove。
          代碼:

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

          配置:

          <bean id="resourceCacheBackend"
                    class
          ="com.framework.extcomponent.cache.MemcachedCacheFactoryBean">
                  
          <property name="cacheManager" ref="memcachedManager"/>
                  
          <property name="cacheName" value="memcache"/>
              
          </bean>
            resourceCache同上,替換新的實(shí)現(xiàn)類(lèi)MemcachedBasedResourceCache即可。

          二、 Session失效的處理
          采用memcached作為httpsession的存儲(chǔ),并不直接保存httpsession對(duì)象,自定義SessionMap,SessionMap直接繼承HashMap,保存SessionMap。

          會(huì)話(huà)膠粘:未失敗轉(zhuǎn)發(fā)的情況下沒(méi)必要在memcached保存的SessionMap和httpsession之間復(fù)制來(lái)復(fù)制去,眉來(lái)眼去。

          利用memcached計(jì)數(shù)器保存在線人數(shù)。

          系統(tǒng)權(quán)限采用了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>


          注意需要配置在第一個(gè)。
          snaFilter的職責(zé):
          1、 沒(méi)有HttpSession時(shí),創(chuàng)建HttpSession;
          2、 創(chuàng)建Cookie保存HttpSession id;
          3、 如果Cookie保存的HttpSession id與當(dāng)前HttpSession id一致,說(shuō)明是正常請(qǐng)求;
          4、 如果Cookie保存的HttpSession id與當(dāng)前HttpSession id不一致,說(shuō)明是失敗轉(zhuǎn)發(fā);失敗轉(zhuǎn)發(fā)的處理:
               4.1、根據(jù)Cookie保存的HttpSession id從memcached獲取SessionMap;
               4.2、SessionMap屬性復(fù)制到當(dāng)前HttpSession;
               4.3、memcached刪除SessionMap。
          5、 判斷當(dāng)前請(qǐng)求url是否是登出url,是則刪除SessionMap,在線人數(shù)減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(
          "開(kāi)始SNA攔截-----------------" + uri);
                  HttpSession httpSession 
          = hrequest.getSession();
                  String sessionId 
          = httpSession.getId();
                  
          //如果是登出,則直接干掉sessionMap
                  if (uri.equals(logoutUrl)) {
                      logger.debug(
          "remove sessionmap:" + sessionId);
                      
          //在線人數(shù)減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監(jiān)聽(tīng)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){
                      
          //在線人數(shù)加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事件時(shí)根據(jù)sessionid刪除memcached里的sessionMap(如果存在)。不再擔(dān)心httpsession的過(guò)期問(wèn)題。
          
          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);
                      
          //在線人數(shù)減1
                      getCache().addOrDecr("userCount",1);
                      getCache().remove(sessionId);
                  }
              }

            三、 文件保存的處理

          和緩存類(lèi)似,采用集中式的文件服務(wù)。對(duì)于linux,采用nfs。參考文檔http://linux.vbird.org/linux_server/0330nfs.php#What_NFS_perm。關(guān)鍵在于對(duì)權(quán)限的分配。
          應(yīng)用程序本身不用修改。




          http://www.aygfsteel.com/ronghao 榮浩原創(chuàng),轉(zhuǎn)載請(qǐng)注明出處:)
          posted on 2008-10-28 20:41 ronghao 閱讀(2508) 評(píng)論(3)  編輯  收藏 所屬分類(lèi): 工作日志

          FeedBack:
          # re: 基于memcached的SNA實(shí)現(xiàn)
          2008-10-29 09:15 | 岑文初
          ^_^,不錯(cuò)  回復(fù)  更多評(píng)論
            
          # re: 基于memcached的SNA實(shí)現(xiàn)
          2008-10-29 09:18 | 岑文初
          對(duì)了,最近修復(fù)了幾個(gè)邊界問(wèn)題,最新版本為2.4  回復(fù)  更多評(píng)論
            
          # re: 基于memcached的SNA實(shí)現(xiàn)[未登錄](méi)
          2008-10-30 09:11 | ronghao
          @岑文初
          呵呵,謝謝。要多向你學(xué)習(xí):)  回復(fù)  更多評(píng)論
            
          <2008年10月>
          2829301234
          567891011
          12131415161718
          19202122232425
          2627282930311
          2345678

          關(guān)注工作流和企業(yè)業(yè)務(wù)流程改進(jìn)?,F(xiàn)就職于ThoughtWorks。新浪微博:http://weibo.com/ronghao100

          常用鏈接

          留言簿(38)

          隨筆分類(lèi)

          隨筆檔案

          文章分類(lèi)

          文章檔案

          常去的網(wǎng)站

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 湘西| 锡林浩特市| 财经| 新津县| 武清区| 普格县| 霍州市| 云浮市| 宁海县| 平武县| 镇江市| 康乐县| 武冈市| 海原县| 乌拉特后旗| 镇平县| 奇台县| 邯郸市| 吴川市| 策勒县| 宁陕县| 兴业县| 武陟县| 巴东县| 余干县| 章丘市| 永定县| 莱西市| 浮梁县| 陈巴尔虎旗| 青阳县| 澎湖县| 仙居县| 东城区| 金寨县| 北海市| 宽甸| 侯马市| 南通市| 新田县| 武隆县|