disconf-註解式分佈式配置

1. 分佈式配置管理平臺Disconf

1.1. 摘要

爲了更好的解決分佈式環境下多臺服務實例的配置統一管理問題,本文提出了一套完整的分佈式配置管理解決方案(簡稱爲disconf[4],下同)。首先,實現了同構系統的配置發佈統一化,提供了配置服務server,該服務能夠對配置進行持久化管理並對外提供restful接口,在此基礎上,基於zookeeper實現對配置更改的實時推送,而且,提供了穩定有效的容災方案,以及用戶體驗良好的編程模型和WEB用戶管理界面。其次,實現了異構系統的配置包管理,提出基於zookeeper的全局分佈式一致性鎖來實現主備統一部署、系統異常時的主備自主切換。經過在百度內部以及外部等多個產品線的實踐結果代表,本解決方案是有效且穩定的。html

1.2. 技術背景

在一個分佈式環境中,同類型的服務每每會部署不少實例。這些實例使用了一些配置,爲了更好地維護這些配置就產生了配置管理服務。經過這個服務能夠輕鬆地管理成千上百個服務實例的配置問題。前端

王阿晶提出了基於zooKeeper的配置信息存儲方案的設計與實現[1], 它將全部配置存儲在zookeeper上,這會致使配置的管理不那麼方便,並且他們沒有相關的源碼實現。淘寶的diamond[2]是淘寶內部使用的一個管理持久配置的系統,它具備完整的開源源碼實現,它的特色是簡單、可靠、易用,淘寶內部絕大多數系統的配置都採用diamond來進行統一管理。他將全部配置文件裏的配置打散化進行存儲,只支持KV結構,而且配置更新的推送是非實時的。百度內部的BJF配置中心服務[3]採用了相似淘寶diamond的實現,也是配置打散化、只支持KV和非實時推送。java

同構系統是市場的主流,特別地,在業界大量使用部署虛擬化(如JPAAS系統,SAE,BAE)的狀況下,同一個系統使用同一個部署包的情景會愈來愈多。可是,異構系統也有必定的存在乎義,譬如,對於「拉模式」的多個下游實例,同一時間點只能只有一個下游實例在運行。在這種情景下,就存在多臺實例機器有「主備機」模式的問題。目前國內並無很明顯的解決方案來統一解決此問題。python

1.3. 功能特色與設計理念

disconf是一套完整的基於zookeeper的分佈式配置統一解決方案。mysql

它的功能特色是linux

  • 支持配置(配置項+配置文件)的分佈式化管理
    • 配置發佈統一化
    • 配置發佈、更新統一化(雲端存儲、發佈):配置存儲在雲端系統,用戶統一在平臺上進行發佈、更新配置。
    • 配置更新自動化:用戶在平臺更新配置,使用該配置的系統會自動發現該狀況,並應用新配置。特殊地,若是用戶爲此配置定義了回調函數類,則此函數類會被自動調用。
  • 配置異構系統管理
    • 異構包部署統一化:這裏的異構系統是指一個系統部署多個實例時,因爲配置不一樣,從而須要多個部署包(jar或war)的狀況(下同)。使用Disconf後,異構系統的部署只須要一個部署包,不一樣實例的配置會自動分配。特別地,在業界大量使用部署虛擬化(如JPAAS系統,SAE,BAE)的狀況下,同一個系統使用同一個部署包的情景會愈來愈多,Disconf能夠很天然地與他自然契合。 異構主備自動切換:若是一個異構系統存在主備機,主機發生掛機時,備機能夠自動獲取主機配置從而變成主機。
    • 異構主備機Context共享工具:異構系統下,主備機切換時可能須要共享Context。可使用Context共享工具來共享主備的Context。
  • 註解式編程,極簡的使用方式:咱們追求的是極簡的、用戶編程體驗良好的編程方式。經過簡單的標註+極簡單的代碼撰寫,便可完成複雜的配置分佈式化。
  • 須要Spring編程環境

它的設計理念是:nginx

  • 簡單,用戶體驗良好:
    • 摒棄了打散化配置的管理方式[2,3],仍舊採用基於配置文件的編程方式,這和程序員之前的編程習慣(配置都是放在配置文件裏)一致。特別的,爲了支持較爲小衆的打散化配置功能,還特別支持了配置項。
    • 採用了基於XML無代碼侵入編程方式:只須要幾行XML配置,便可實現配置文件發佈更新統一化、自動化。
    • 採用了基於註解式的弱代碼侵入編程方式:經過編程規範,一個配置文件一個配置類,代碼結構簡單易懂。XML幾乎沒有任何更改,與原springXML配置同樣。真正編程時,幾乎感受不到配置已經分佈式化
  • 能夠託管任何類型的配置文件,這與[2,3]只能支持KV結構的功能有較大的改進。
  • 配置更新實時推送
  • 提供界面良好Web管理功能,能夠很是方便的查看配置被哪些實例使用了。

1.4. 詳細設計

架構設計

disconf服務集羣模式git

image0

disconf的模塊架構圖程序員

image1

每一個模塊的簡單介紹以下:github

  • Disconf-core
    • 分佈式通知模塊:支持配置更新的實時化通知
    • 路徑管理模塊:統一管理內部配置路徑URL
  • Disconf-client
    • 配置倉庫容器模塊:統一管理用戶實例中本地配置文件和配置項的內存數據存儲
    • 配置reload模塊:監控本地配置文件的變更,並自動reload到指定bean
    • 掃描模塊:支持掃描全部disconf註解的類和域
    • 下載模塊:restful風格的下載配置文件和配置項
    • watch模塊:監控遠程配置文件和配置項的變化
    • 主備分配模塊:主備競爭結束後,統一管理主備分配與主備監控控制
    • 主備競爭模塊:支持分佈式環境下的主備競爭
  • Disconf-web
    • 配置存儲模塊:管理全部配置的存儲和讀取
    • 配置管理模塊:支持配置的上傳、下載、更新
    • 通知模塊:當配置更新後,實時通知使用這些配置的全部實例
    • 配置自檢監控模塊:自動定時校驗實例本地配置與中心配置是否一致
    • 權限控制:web的簡單權限控制
  • Disconf-tools
    • context共享模塊:提供多實例間context的共享。

流程設計

image2

運行流程詳細介紹:

與2.0版本的主要區別是支持了:主備分配功能/主備切換事件。

  • 啓動事件A:如下按順序發生。
    • A3:掃描靜態註解類數據,並注入到配置倉庫裏。
    • A4+A2:根據倉庫裏的配置文件、配置項,去 disconf-web 平臺裏下載配置數據。這裏會有主備競爭
    • A5:將下載獲得的配置數據值注入到倉庫裏。
    • A6:根據倉庫裏的配置文件、配置項,去ZK上監控結點。
    • A7+A2:根據XML配置定義,到 disconf-web 平臺裏下載配置文件,放在倉庫裏,並監控ZK結點。這裏會有主備競爭。
    • A8:A1-A6均是處理靜態類數據。A7是處理動態類數據,包括:實例化配置的回調函數類;將配置的值注入到配置實體裏。
  • 更新配置事件B:如下按順序發生。
    • B1:管理員在 Disconf-web 平臺上更新配置。
    • B2:Disconf-web 平臺發送配置更新消息給ZK指定的結點。
    • B3:ZK通知 Disconf-cient 模塊。
    • B4:與A4同樣。
    • B5:與A5同樣。
    • B6:基本與A4同樣,惟一的區別是,這裏還會將配置的新值注入到配置實體裏。
  • 主備機切換事件C:如下按順序發生。
    • C1:發生主機掛機事件。
    • C2:ZK通知全部被影響到的備機。
    • C4:與A2同樣。
    • C5:與A4同樣。
    • C6:與A5同樣。
    • C7:與A6同樣。

模塊實現

disconf-web提供了先後端分離的web架構,具體可見:

https://github.com/knightliao/disconf/tree/master/disconf-web

本部分會重點介紹disconf-client的實現方式。

註解式disconf實現

本實現會涉及到 配置倉庫容器模塊、掃描模塊、下載模塊、watch模塊,

http://ww1.sinaimg.cn/bmiddle/60c9620fjw1eqj9zzgc7yj20b20pn41v.jpg

使用AOP攔截的一個好處是能夠比較輕鬆的實現配置控制,好比並發環境下的配置統一輩子效。關於這方面的討論能夠見這裏

特別地,本方式提供的編程模式很是簡單,例如使用如下配置類的程序在使用它時,能夠直接@Autowired進來進行調用,使用它時就和日常使用普通的JavaBean同樣,但其實它已經分佈式化了。配置更新時,配置類亦會自動更新。

@Service
@DisconfFile(filename = "redis.properties")
public class JedisConfig {

    // 表明鏈接地址
    private String host;

    // 表明鏈接port
    private int port;

    /**
     * 地址, 分佈式文件配置
     *
     * @return
     */
    @DisconfFileItem(name = "redis.host", associateField = "host")
    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    /**
     * 端口, 分佈式文件配置
     *
     * @return
     */
    @DisconfFileItem(name = "redis.port", associateField = "port")
    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }
}

基於XML配置disconf實現

本實現提供了無任何代碼侵入方式的分佈式配置。

ReloadablePropertiesFactoryBean繼承了Spring Properties文件的PropertiesFactoryBean類,管理全部當配置更新時要進行reload的配置文件。對於被管理的每個配置文件,都會經過 配置倉庫容器模塊、掃描模塊、下載模塊、watch模塊 進行配置獲取至配置倉庫裏。

ReloadingPropertyPlaceholderConfigurer繼承了Spring Bean配置值控制類PropertyPlaceholderConfigurer。在第一次掃描spring bean 時,disconf會記錄配置文件的配置與哪些bean有關聯。

ReloadConfigurationMonitor是一個定時任務,定時check本地配置文件是否有更新。

當配置中心的配置被更新時,配置文件會被下載至實例本地,ReloadConfigurationMonitor即會監控到此行爲,而且通知 ReloadingPropertyPlaceholderConfigurer 對相關的bean類進行值更新。

特別的,此種方式沒法解決併發狀況下配置統一輩子效的問題。

主備分配實現

在實現中,爲每一個配置提供主備選擇的概念。用戶實例在獲取配置前須要先進行全局惟一性競爭才能獲得配置值。在這裏,咱們採用基於zookeeper的全局惟一性鎖來實現。

1.5. Comparisons

  淘寶Diamond[2] Disconf 比較
數據持久性 存儲在mysql上 存儲在mysql上 都持久化到數據庫裏,都易於管理
推拉模型 拉模型,每隔15s拉一次全量數據 基於Zookeeper的推模型,實時推送 disconf基於分佈式的Zookeeper來實時推送,不斷是在穩定性、實效性、易用性上均優於diamond
配置讀寫 支持實例對配置讀寫。支持某臺實例寫配置數據,並廣播到其它實例上 只支持實例對配置讀。經過在disconf-web上更新配置到達到廣播寫到全部應用實例 從目前的應用場景來看,實例對配置的寫需求不是那麼明顯。disconf支持的中心化廣播方案可能會與人性思考更加類似。
容災 多級容災模式,配置數據會dump在本地,避免中心服務掛機時沒法使用 多級容災模式,優先讀取本地配置文件。 雙方均支持在中心服務掛機時配置實例仍然可使用
配置數據模型 只支持KV結構的數據,非配置文件模式 支持傳統的配置文件模式(配置文件),亦支持KV結構數據(配置項) 使用配置文件的編程方式可能與程序員的編程習慣更爲類似,更易於接受和使用。
編程模型 須要將配置文件拆成多個配置項,沒有明顯的編程模型 在使用配置文件的基礎上,提供了註解式和基於XML的兩種編程模型
併發性 多條配置要同時生效時,沒法解決併發同時生效的問題 基於註解式的配置,能夠解決併發性問題

1.6. Reference

  1. 王阿晶,鄒仕洪: 基於ZooKeeper的配置信息存儲方案的設計與實現
  2. 淘寶diamod實現:http://code.taobao.org/p/diamond/src/, 2012
  3. 百度BJF配置中心, 2014
  4. disconf github: https://github.com/knightliao/disconf, 2014
  5. 淘寶分佈式配置管理服務Diamond
  6. zooKeeper和Diamond有什麼不一樣
  7. diamond專題(一)– 簡介和快速使用

具體使用以下:

 

2.搭建項目

 --就是一個disconf-web

2.1安裝依賴軟件

  • 安裝Mysql(Ver 14.12 Distrib 5.0.45, for unknown-linux-gnu (x86_64) using EditLine wrapper)
  • 安裝Tomcat(apache-tomcat-7.0.50)
  • 安裝Nginx(nginx/1.5.3)
  • 安裝 zookeeeper (zookeeper-3.3.0)
  • 安裝 Redis (2.4.5)

2.2準備配置

將你的配置文件放到此地址目錄下(如下地址可自行設定):

home/work/dsp/disconf-rd/online-resources

配置文件包括:

- jdbc-mysql.properties (數據庫配置)
- redis-config.properties (Redis配置)
- zoo.properties (Zookeeper配置)
- application.properties (應用配置)

注意,記得執行將application-demo.properties複製成application.properties:

cp application-demo.properties application.properties

設置War包將要被部署的地址(如下地址可自行設定):

/home/work/dsp/disconf-rd/war

2.3構建

ONLINE_CONFIG_PATH=/home/work/dsp/disconf-rd/online-resources
WAR_ROOT_PATH=/home/work/dsp/disconf-rd/war
export ONLINE_CONFIG_PATH
export WAR_ROOT_PATH
cd disconf-web
sh deploy/deploy.sh

這樣會在 /home/work/dsp/disconf-rd/war 生成如下結果:

-disconf-web.war  
-html  
-META-INF  
-WEB-INF

2.4上線前的初始化工做

初始化數據庫:

能夠參考 sql/readme.md 來進行數據庫的初始化。

裏面默認有6個用戶

若是想本身設置初始化的用戶名信息,能夠參考代碼來本身生成用戶:

src/main/java/com/baidu/disconf/web/tools/UserCreateTools.java

2.5部署War

修改server.xml文件,在Host結點下設定Context:

<Context path="" docBase="/home/work/dsp/disconf-rd/war"></Context>

並設置端口爲 8015

啓動Tomcat,便可。

2.6部署 前端

修改 nginx.conf

upstream disconf {
    server 127.0.0.1:8015;
}

server {

    listen   8081;
    server_name localhost;
    access_log /home/work/var/logs/disconf/access.log;
    error_log /home/work/var/logs/disconf/error.log;

    location / {
        root /home/work/dsp/disconf-rd/war/html;
        if ($query_string) {
            expires max;
        }
    }

    location ~ ^/(api|export) {
        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_pass http://disconf;
    }
}

特別指出在打包項目時候請檢查python庫版本3.*版本會報錯,請用2.*打包

第二點,在打出來的war包修改諸如zookeeper的配置時,必須從新打包,單純修改war目錄下的文件是無效的

2.7使用

用戶名密碼 admin/admin

建立app,上傳配置


1.添加disconf.properties配置文件

  disconf.user_define_download_dir=./                                 此處意思就是將zookeeper中的配置拉到本地的classpath下,若配置成其餘目錄,彷佛會報錯

Java代碼 

  1. disconf.enable.remote.conf=true  
  2. disconf.conf_server_host=172.171.51.151:8082  
  3. disconf.version=1.0.0.0  
  4. disconf.app=17wifiServer  
  5. disconf.env=local  
  6. disconf.ignore=  
  7. disconf.conf_server_url_retry_times=1  
  8. disconf.conf_server_url_retry_sleep_seconds=1  
  9. disconf.user_define_download_dir=./  
  10. disconf.enable_local_download_dir_in_class_path=true  

 

2.添加disconf.xml,而且指定給spring加載

配置以下

Java代碼 

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2.   
  3. <beans xmlns="http://www.springframework.org/schema/beans"  
  4.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"  
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans  
  6.         http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  
  7.         http://www.springframework.org/schema/aop  
  8.         http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">  
  9.     <aop:aspectj-autoproxy proxy-target-class="true"/>  
  10.     <!-- 使用disconf必須添加如下配置 -->  
  11.     <bean id="disconfMgrBean" class="com.baidu.disconf.client.DisconfMgrBean"  
  12.           destroy-method="destroy">  
  13.         <property name="scanPackage" value="com.fnic.wifi.server"/>  
  14.     </bean>  
  15.     <bean id="disconfMgrBean2" class="com.baidu.disconf.client.DisconfMgrBeanSecond"  
  16.           init-method="init" destroy-method="destroy">  
  17.     </bean>  
  18.     <!--################################################################ -->  
  19.     <!-- 使用託管方式的disconf配置(無代碼侵入, 配置更改會自動reload)-->  
  20.     <bean id="configproperties_disconf"  
  21.           class="com.baidu.disconf.client.addons.properties.ReloadablePropertiesFactoryBean">  
  22.         <property name="locations">  
  23.             <list>  
  24.                                 <value>classpath:jdbc.properties</value>  
  25.                 <value>classpath:redis.properties</value>  
  26.             </list>  
  27.         </property>  
  28.     </bean>  
  29.     <bean id="propertyConfigurer"  
  30.           class="com.baidu.disconf.client.addons.properties.ReloadingPropertyPlaceholderConfigurer">  
  31.         <property name="ignoreResourceNotFound" value="true"/>  
  32.         <property name="ignoreUnresolvablePlaceholders" value="true"/>  
  33.         <property name="propertiesArray">  
  34.             <list>  
  35.                 <ref bean="configproperties_disconf"/>  
  36.             </list>  
  37.         </property>  
  38.     </bean>    
  39. </beans>  

 配置上半段是必須配置,下半段是將配置文件託管給spring,而且能夠運用${}這樣的形式配置在spring的xml中,能夠參考jdbc數據源的配置

其中

Java代碼 

  1. <value>classpath:jdbc.properties</value>  
  2. <value>classpath:redis.properties</value>  
  3. 要和上面  
  4. disconf.user_define_download_dir=./ 對應起來 

 

3.註釋掉spring本來的加載配置類

Java代碼 

  1. <!--     <bean id="config"  
  2.         class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
  3.         <property name="locations">  
  4.             <list>  
  5.                 <value>classpath:conf/jdbc.properties</value>  
  6.                 <value>classpath:conf/redis.properties</value>  
  7.             </list>  
  8.         </property>  
  9.     </bean> -->    

 4.編寫測試bean

Java代碼

  1. @Component  
  2. @DisconfFile(filename = "configure.properties")  
  3. public class ConfDIs {  
  4.     private String resourceUrl;  
  5.   
  6.     @DisconfFileItem(name = "resource_server_url", associateField = "resourceUrl")  
  7.     public String getResourceUrl() {  
  8.         return resourceUrl;  
  9.     }  
  10.   
  11.     public void setResourceUrl(String resourceUrl) {  
  12.         this.resourceUrl = resourceUrl;  
  13.     }  
  14.   
  15. }  

 

ok啓動就能夠運用disconf了,其性能還有待驗證,不過其原理應該是從zk中拉配置到本地內存中,同本身手動加載本地的property文件。

正常的日誌以下

Java代碼 

  1. 2016-04-27 17:57:27 [com.baidu.disconf.client.DisconfMgr]-[INFO] ******************************* DISCONF END FIRST SCAN *******************************  
  2. 2016-04-27 17:57:28 [org.springframework.beans.GenericTypeAwarePropertyDescriptor]-[WARN] Invalid JavaBean property 'locations' being accessed! Ambiguous write methods found next to actually used [public void com.baidu.disconf.client.addons.properties.ReloadablePropertiesFactoryBean.setLocations(java.util.List)]: [public void org.springframework.core.io.support.PropertiesLoaderSupport.setLocations(org.springframework.core.io.Resource[])]  
  3. 2016-04-27 17:57:28 [com.baidu.disconf.client.addons.properties.ReloadablePropertiesFactoryBean]-[INFO] Loading properties file from class path resource [jdbc.properties]  
  4. 2016-04-27 17:57:28 [com.baidu.disconf.client.addons.properties.ReloadablePropertiesFactoryBean]-[INFO] Loading properties file from class path resource [redis.properties]  
  5. 2016-04-27 17:57:28 [org.springframework.beans.factory.support.DefaultListableBeanFactory]-[INFO] Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@63b7e77: defining beans [wifiAspect,activityDataBuilder,apActiveManageController,adDataBuilder,apAdController,apResourceController,resourceDataBuilder,apUserController,busController,busOnlineController,clickStatistics,confDIs,couponController,apFeedBackController,apFindAroundController,indexController,splashDataBuilder,messageSendController,sendMailController,pluginController,appScoreController,versionController,wifiAuthController,startListener,busServiceImpl,activityServiceImpl,apAdServiceImpl,apFeedBackSeriveImpl,appScoreServiceImpl,apResourceServiceImpl,apUserServiceImpl,busOnlineServiceImpl,couponServiceImpl,DAServiceImpl,findAroundServiceImpl,groupServiceImpl,indexServiceImpl,messageSendServiceImpl,pluginServiceImpl,versionServiceImpl,wifiAuthServiceImpl,httpService,springHolder,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,jedisPoolConfig,jedisConnFactory,stringRedisTemplate,objRedisTemplate,redisObj,redisString,redisTemplate,redisSubscribe,messageDelegateListener,serialization,messageListener,redisContainer,dataSource,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,sqlSessionFactory,org.mybatis.spring.mapper.MapperScannerConfigurer#0,transactionManager,disconfMgrBean,disconfMgrBean2,configproperties_disconf,propertyConfigurer,disconfAspectJ,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor,activityDao,apAdDao,apFeedBackDao,appScoreDao,apResourceDao,apUserDao,busDao,busOnlineDao,couponDao,DADao,findAroundDao,groupDao,indexDao,messageSendDao,pluginDao,versionDao,wifiAuthDao]; root of factory hierarchy  
  6. 2016-04-27 17:57:28 [com.fnic.wifi.server.aop.WifiAspect]-[INFO] 初始化Controller Aop  
  7. 2016-04-27 17:57:30 [com.baidu.disconf.client.DisconfMgr]-[INFO] ******************************* DISCONF START SECOND SCAN *******************************  
  8. 2016-04-27 17:57:30 [com.baidu.disconf.client.DisconfMgr]-[INFO] Conf File Map:   
  9. disconf-file:   redis.properties      
  10.     DisconfCenterFile [  
  11.     keyMaps={}  
  12.     additionalKeyMaps={redis.maxWait=3000, redis.hostName=172.171.51.154, redis.maxIdle=5, redis.port=6380, redis.maxActive=500}  
  13.     cls=null  
  14.     remoteServerUrl=/api/config/file?app=17wifiServer&env=local&type=0&key=redis.properties&version=1.0.0.0]  
  15. disconf-file:   jdbc.properties   
  16.     DisconfCenterFile [  
  17.     keyMaps={}  
  18.     additionalKeyMaps={jdbc.url=jdbc:mysql://172.171.48.110:3306/wifimanage?characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull, jdbc.minIdle=5, jdbc.username=root, jdbc.maxWait=3000, jdbc.removeAbandoned=true, jdbc.maxActive=15, jdbc.removeAbandonedTimeout=300, jdbc.maxIdle=30, jdbc.logAbandoned=true, jdbc.driver=com.mysql.jdbc.Driver, jdbc.password=root}  
  19.     cls=null  
  20.     remoteServerUrl=/api/config/file?app=17wifiServer&env=local&type=0&key=jdbc.properties&version=1.0.0.0]  
  21. disconf-file:   configure.properties      
  22.     DisconfCenterFile [  
  23.     keyMaps={resource_server_url=FileItemValue{value=http://172.171.51.151:8081/Resources2/, field=private java.lang.String com.fnic.wifi.server.controller.ConfDIs.resourceUrl, setMethod=null}}  
  24.     additionalKeyMaps={}  
  25.     cls=class com.fnic.wifi.server.controller.ConfDIs  
  26.     remoteServerUrl=/api/config/file?app=17wifiServer&env=local&type=0&key=configure.properties&version=1.0.0.0]  
  27.   
  28. 2016-04-27 17:57:30 [com.baidu.disconf.client.DisconfMgr]-[INFO] Conf Item Map:   
  29.   
  30. 2016-04-27 17:57:30 [com.baidu.disconf.client.DisconfMgr]-[INFO] ******************************* DISCONF END *******************************  

3.參考

http://disconf.readthedocs.io/zh_CN/latest/ 

相關文章
相關標籤/搜索