<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 193,  comments - 520,  trackbacks - 0

    系統(tǒng)要集群,使用SNA方案。
    一、 緩存的處理
    緩存要使用統(tǒng)一的緩存服務(wù)器,集中式緩存。
    原先的實現(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é)對ehcache進行管理,初始化、啟動、停止。
    resourceCacheBackend負(fù)責(zé)實際執(zhí)行緩存操作,put 、get、remove。
    resourceCache實現(xiàn)具有業(yè)務(wù)語義的業(yè)務(wù)應(yīng)用層面的緩存操作,內(nèi)部調(diào)用resourceCacheBackend操作。

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

    /**
    * 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é)實際執(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同上,替換新的實現(xiàn)類MemcachedBasedResourceCache即可。

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

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

    利用memcached計數(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>


    注意需要配置在第一個。
    snaFilter的職責(zé):
    1、 沒有HttpSession時,創(chuàng)建HttpSession;
    2、 創(chuàng)建Cookie保存HttpSession id;
    3、 如果Cookie保存的HttpSession id與當(dāng)前HttpSession id一致,說明是正常請求;
    4、 如果Cookie保存的HttpSession id與當(dāng)前HttpSession id不一致,說明是失敗轉(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)前請求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(
    "開始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)聽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事件時根據(jù)sessionid刪除memcached里的sessionMap(如果存在)。不再擔(dān)心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);
                
    //在線人數(shù)減1
                getCache().addOrDecr("userCount",1);
                getCache().remove(sessionId);
            }
        }

      三、 文件保存的處理

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




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

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

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

    常用鏈接

    留言簿(38)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    常去的網(wǎng)站

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 女人18毛片特级一级免费视频| 亚洲欧美日韩中文高清www777| 中文字幕亚洲色图| 国产高清免费在线| 国产a视频精品免费观看| 国产成人高清精品免费观看| 亚洲精品无码久久久久久| 久久亚洲日韩精品一区二区三区| 午夜免费福利片观看| 日韩毛片在线免费观看| 亚洲成av人片不卡无码久久| 中文字幕免费在线视频| 女bbbbxxxx另类亚洲| 亚洲人成人网毛片在线播放| 亚洲AV无码国产精品色午友在线 | 亚洲人成在线影院| 亚洲一区精品无码| 亚洲成a人片在线观看久| 国产精品久免费的黄网站| 日韩免费a级毛片无码a∨ | 国产无遮挡裸体免费视频在线观看| 美女视频黄a视频全免费网站色| 亚洲日韩AV一区二区三区中文| 亚洲欧洲精品久久| 亚洲美女人黄网成人女| 亚洲精品高清视频| 久久久久亚洲Av无码专| 亚洲AV区无码字幕中文色| 免费看大美女大黄大色| 成人免费av一区二区三区| 皇色在线免费视频| www在线观看播放免费视频日本| 十八禁的黄污污免费网站| 免费的黄色的网站| 久久久久久久久久久免费精品| 国产免费AV片在线观看播放| 国产久爱免费精品视频| 中文字字幕在线高清免费电影| 99免费在线视频| 麻豆精品不卡国产免费看| 69视频免费在线观看|