02铲觉、攜程Apollo Java客戶端使用指南

一澈蝙、 客戶端設(shè)計(jì)

image.png

上圖簡(jiǎn)要描述了Apollo客戶端的實(shí)現(xiàn)原理
1、客戶端和服務(wù)端保持了一個(gè)長(zhǎng)連接撵幽,從而能第一時(shí)間獲得配置更新的推送灯荧。(通過Http Long Polling實(shí)現(xiàn))
2、客戶端還會(huì)定時(shí)從Apollo配置中心服務(wù)端拉取應(yīng)用的最新配置盐杂。
(1)逗载、這是一個(gè)fallback機(jī)制,為了防止推送機(jī)制失效導(dǎo)致配置不更新
(2)链烈、客戶端定時(shí)拉取會(huì)上報(bào)本地版本厉斟,所以一般情況下,對(duì)于定時(shí)拉取的操作强衡,服務(wù)端都會(huì)返回304-Not Modified
(3)擦秽、定時(shí)頻率默認(rèn)為每5分鐘拉取一次,客戶端也可以通過在運(yùn)行是指定System Property:apollo.refreshInterval來覆蓋食侮,單位為分鐘
(4)号涯、客戶端會(huì)把從服務(wù)端獲取到的配置在本地文件緩存一份
遇到服務(wù)不可用,或網(wǎng)絡(luò)不通的時(shí)候锯七,依然能從本地恢復(fù)配置
(5)、應(yīng)用程序可以從Apollo客戶端獲取最新的配置誉己、訂閱配置更新通知

二眉尸、 準(zhǔn)備工作

1、環(huán)境要求

Java1.7+
Guava15.0+ : Apollo客戶端默認(rèn)會(huì)引用Guava 19巨双,如果你的項(xiàng)目引用了其它版本噪猾,請(qǐng)確保版本號(hào)大于等于15.0
注:對(duì)于Apollo客戶端,如果有需要的話筑累,可以做少量代碼修改來降級(jí)到Java 1.6,如需更改可以參照官方說明Issue 483

2袱蜡、必選設(shè)置

Apollo客戶端依賴于AppId, Apollo Meta Server等環(huán)境信息來工作,所以請(qǐng)確保閱讀下面的說明并且做正確的配置:

(1)慢宗、AppId

AppId是應(yīng)用的身份信息坪蚁,是從服務(wù)端獲取配置的一個(gè)重要信息奔穿。
有以下3種方式設(shè)置,按照優(yōu)先級(jí)從高到低分別為:

A: System Property

Apollo 0.7.0+支持通過System Property傳入app.id信息敏晤,如:

-Dapp.id=YOUR-APP-ID

B: Spring Boot application.properties

Apollo 1.0.0+支持通過Spring Boot的application.properties文件配置贱田,如

app.id=YOUR-APP-ID

C: app.properties

確保classpath:/META-INF/app.properties文件存在,并且其中內(nèi)容形如:

app.id=YOUR-APP-ID
image.png

注:app.id是用來標(biāo)識(shí)應(yīng)用身份的唯一id嘴脾,格式為string男摧。

(2)、Apollo Meta Server

Apollo支持應(yīng)用在不同的環(huán)境有不同的配置译打,所以需要在運(yùn)行提供給Apollo客戶端當(dāng)前環(huán)境的Apollo Meta Server信息耗拓。默認(rèn)情況下,meta server和config service是部署在同一個(gè)JVM進(jìn)程奏司,所以meta server的地址就是config service的地址帆离。
為了實(shí)現(xiàn)meta server的高可用,推薦通過SLB(Software Load Balancer)做動(dòng)態(tài)負(fù)載均衡结澄。Meta server地址也可以填入IP哥谷,如http://1.1.1.1:8080,http://2.2.2.2:8080,不過生產(chǎn)環(huán)境還是建議使用域名(走slb)麻献,因?yàn)闄C(jī)器擴(kuò)容们妥、縮容等都可能導(dǎo)致IP列表的變化。
1.0.0版本開始支持以下方式配置apollo meta server信息勉吻,按照優(yōu)先級(jí)從高到低分別為:

A:通過Java System Property apollo.meta

可以通過Java的System Property apollo.meta來指定
在Java程序啟動(dòng)腳本中监婶,可以指定-Dapollo.meta=http://config-service-url
如果是運(yùn)行jar文件,需要注意格式是java -Dapollo.meta=http://config-service-url -jar xxx.jar
也可以通過程序指定齿桃,如System.setProperty("apollo.meta", "http://config-service-url");

B:通過Spring Boot的配置文件

可以在Spring Boot的application.propertiesbootstrap.properties中指定apollo.meta=http://config-service-url

C:通過操作系統(tǒng)的System EnvironmentAPOLLO_META

可以通過操作系統(tǒng)的System Environment APOLLO_META來指定
注意key為全大寫惑惶,且中間是_分隔

D:通過server.properties配置文件

可以在server.properties配置文件中指定apollo.meta=http://config-service-url
對(duì)于Mac/Linux,文件位置為/opt/settings/server.properties
對(duì)于Windows短纵,文件位置為C:\opt\settings\server.properties

E:通過app.properties配置文件

可以在classpath:/META-INF/app.properties指定apollo.meta=http://config-service-url

F:通過Java system property ${env}_meta

如果當(dāng)前env是dev带污,那么用戶可以配置-Ddev_meta=http://config-service-url
使用該配置方式,那么就必須要正確配置Environment

G:通過操作系統(tǒng)的System Environment ${ENV}_META (1.2.0版本開始支持)

如果當(dāng)前env是dev香到,那么用戶可以配置操作系統(tǒng)的System Environment DEV_META=http://config-service-url
注意key為全大寫
使用該配置方式鱼冀,那么就必須要正確配置Environment

H:通過apollo-env.properties文件

用戶也可以創(chuàng)建一個(gè)apollo-env.properties,放在程序的classpath下悠就,或者放在spring boot應(yīng)用的config目錄下
使用該配置方式千绪,那么就必須要正確配置Environment
文件內(nèi)容形如:

dev.meta=http://1.1.1.1:8080
fat.meta=http://apollo.fat.xxx.com
uat.meta=http://apollo.uat.xxx.com
pro.meta=http://apollo.xxx.com

如果通過以上各種手段都無法獲取到Meta Server地址,Apollo最終會(huì)fallback到http://apollo.meta作為Meta Server地址
3梗脾、本地緩存路徑
Apollo客戶端會(huì)把從服務(wù)端獲取到的配置在本地文件系統(tǒng)緩存一份荸型,用于在遇到服務(wù)不可用,或網(wǎng)絡(luò)不通的時(shí)候炸茧,依然能從本地恢復(fù)配置瑞妇,不影響應(yīng)用正常運(yùn)行稿静。
本地緩存路徑默認(rèn)位于以下路徑,所以請(qǐng)確保/opt/data或C:\opt\data\目錄存在踪宠,且應(yīng)用有讀寫權(quán)限自赔。

Mac/Linux: /opt/data/{appId}/config-cache
Windows: C:\opt\data\{appId}\config-cache

4、Environment

Environment可以通過以下3種方式的任意一個(gè)配置:

(1)柳琢、通過Java System Property

可以通過Java的System Property env來指定環(huán)境
在Java程序啟動(dòng)腳本中绍妨,可以指定-Denv=YOUR-ENVIRONMENT
如果是運(yùn)行jar文件,需要注意格式是java -Denv=YOUR-ENVIRONMENT -jar xxx.jar
注意key為全小寫

(2)柬脸、通過操作系統(tǒng)的System Environment

還可以通過操作系統(tǒng)的System Environment ENV來指定
注意key為全大寫
通過配置文件

(3)他去、最后一個(gè)推薦的方式是通過配置文件來指定env=YOUR-ENVIRONMENT

對(duì)于Mac/Linux,文件位置為/opt/settings/server.properties
對(duì)于Windows倒堕,文件位置為C:\opt\settings\server.properties
文件內(nèi)容形如:

env=DEV

目前灾测,env支持以下幾個(gè)值(大小寫不敏感):
DEV:Development environment
FAT:Feature Acceptance Test environment
UAT:User Acceptance Test environment
PRO:Production environment

三、 Maven依賴

在項(xiàng)目中引入maven依賴

 <dependency>
 <groupId>com.ctrip.framework.apollo</groupId>
 <artifactId>apollo-client</artifactId>
 <version>1.1.0</version>
 </dependency>

四垦巴、 客戶端用法

Apollo支持API方式和Spring整合方式媳搪,該怎么選擇用哪一種方式?
API方式靈活骤宣,功能完備秦爆,配置值實(shí)時(shí)更新(熱發(fā)布),支持所有Java環(huán)境憔披。
Spring方式接入簡(jiǎn)單等限,結(jié)合Spring有N種酷炫的玩法,如
前提是需要將Config交由Spring管理


image.png

Placeholder方式:
代碼中使用芬膝,如:@Value("{someKeyFromApollo:someDefaultValue}") application.properties中使用露该,如: spring.datasource.url:{someKeyFromApollo:someDefaultValue}
Spring boot的@ConfigurationProperties方式

image.png

從v0.10.0開始的版本支持placeholder在運(yùn)行時(shí)自動(dòng)更新疹吃,具體參見PR #972挠铲。(v0.10.0之前的版本在配置變化后不會(huì)重新注入甜橱,需要重啟才會(huì)更新,如果需要配置值實(shí)時(shí)更新锈遥,可以參考后續(xù)3.2.2 Spring Placeholder的使用的說明)
Spring方式也可以結(jié)合API方式使用纫事,如注入Apollo的Config對(duì)象,就可以照常通過API方式獲取配置了:
@ApolloConfig
private Config config; //inject config for namespace application

1所灸、API使用方式

API方式是最簡(jiǎn)單、高效使用Apollo配置的方式炫七,不依賴Spring框架即可使用爬立。

(1)、獲取默認(rèn)namespace的配置(application)

Config config = ConfigService.getAppConfig(); //config instance is singleton for each namespace and is never null
String someKey = "someKeyFromDefaultNamespace";
String someDefaultValue = "someDefaultValueForTheKey";
String value = config.getProperty(someKey, someDefaultValue);

通過上述的config.getProperty可以獲取到someKey對(duì)應(yīng)的實(shí)時(shí)最新的配置值万哪。
另外侠驯,配置值從內(nèi)存中獲取抡秆,所以不需要應(yīng)用自己做緩存。

(2)吟策、獲取公共namespace的配置

String somePublicNamespace = "CAT";
Config config = ConfigService.getConfig(somePublicNamespace); //config instance is singleton for each namespace and is never null
String someKey = "someKeyFromPublicNamespace";
String someDefaultValue = "someDefaultValueForTheKey";
String value = config.getProperty(someKey, someDefaultValue);

(3)儒士、獲取非properties格式namespace的配置

String someNamespace = "test";
ConfigFile configFile = ConfigService.getConfigFile(someNamespace, ConfigFileFormat.YML);
String content = configFile.getContent();
System.out.println(content);

2、基于java配置

注意@EnableApolloConfig要和@Configuration一起使用檩坚,不然不會(huì)生效着撩。

(1)、注入默認(rèn)namespace的配置到Spring中

//這個(gè)是最簡(jiǎn)單的配置形式匾委,一般應(yīng)用用這種形式就可以了拖叙,用來指示Apollo注入application namespace的配置到Spring環(huán)境中
@Configuration
@EnableApolloConfig
public class AppConfig {

}
image.png

(2)、注入多個(gè)namespace的配置到spring中

@Configuration
@EnableApolloConfig // 注意@EnableApolloConfig要和@Configuration一起使用赂乐,不然不會(huì)生效薯鳍。
public class ApolloConfig {

}
@Configuration
@EnableApolloConfig(value = {"TEST1.sys_application","sys_application"})
public class AnotherAppConfig {

}

(3)、注入多個(gè)namespace挨措,并且指定順序

@Configuration
@EnableApolloConfig(order = 1) // 注意@EnableApolloConfig要和@Configuration一起使用挖滤,不然不會(huì)生效。
public class ApolloConfig {

}
@Configuration
@EnableApolloConfig(value = {"TEST1.sys_application","sys_application"}, order = 2)
public class AnotherAppConfig {

}

3浅役、Spring Boot集成方式

Spring Boot除了支持上述兩種集成方式以外斩松,還支持通過application.properties/bootstrap.properties來配置,該方式能使配置在更早的階段注入担租,比如使用@ConditionalOnProperty的場(chǎng)景或者是有一些spring-boot-starter在啟動(dòng)階段就需要讀取配置做一些事情(如dubbo-spring-boot-project)砸民,所以對(duì)于Spring Boot環(huán)境建議通過以下方式來接入Apollo(需要0.10.0及以上版本)。
使用方式很簡(jiǎn)單奋救,只需要在application.properties/bootstrap.properties中按照如下樣例配置即可岭参。

(1)、注入默認(rèn)application namespace的配置示例

# will inject 'application' namespace in bootstrap phase
apollo.bootstrap.enabled = true

(2)尝艘、注入非默認(rèn)application namespace或多個(gè)namespace的配置示例

apollo.bootstrap.enabled = true
# will inject 'application' and 'FX.apollo' namespaces in bootstrap phase
apollo.bootstrap.namespaces = application,FX.apollo

注:紅色部分的書寫順序決定了優(yōu)先級(jí)

4演侯、Spring Annotation支持

Apollo同時(shí)還增加了幾個(gè)新的Annotation來簡(jiǎn)化在Spring環(huán)境中的使用。
@ApolloConfig
用來自動(dòng)注入Config對(duì)象
@ApolloConfigChangeListener
用來自動(dòng)注冊(cè)ConfigChangeListener
@ApolloJsonValue
用來把配置的json字符串自動(dòng)注入為對(duì)象
使用樣例如下

public class TestApolloAnnotationBean {
 @ApolloConfig
 private Config config; //inject config for namespace application
 @ApolloConfig("application")
 private Config anotherConfig; //inject config for namespace application
 @ApolloConfig("FX.apollo")

 private Config yetAnotherConfig; //inject config for namespace FX.apollo

 /**
 * ApolloJsonValue annotated on fields example, the default value is specified as empty list - []
 * <br />
 * jsonBeanProperty=[{"someString":"hello","someInt":100},{"someString":"world!","someInt":200}]
 */
 @ApolloJsonValue("${jsonBeanProperty:[]}")
 private List<JsonBean> anotherJsonBeans;

 @Value("${batch:100}")
 private int batch;

 //config change listener for namespace application
 @ApolloConfigChangeListener
 private void someOnChange(ConfigChangeEvent changeEvent) {

 //update injected value of batch if it is changed in Apollo
 if (changeEvent.isChanged("batch")) {
 batch = config.getIntProperty("batch", 100);
 }
 }
 //config change listener for namespace application
 @ApolloConfigChangeListener("application")
 private void anotherOnChange(ConfigChangeEvent changeEvent) {
 //do something

 }
 //config change listener for namespaces application and FX.apollo
 @ApolloConfigChangeListener({"application", "FX.apollo"})
 private void yetAnotherOnChange(ConfigChangeEvent changeEvent) 
 //do something
 }
 //example of getting config from Apollo directly
 //this will always return the latest value of timeout
 public int getTimeout() {
 return config.getIntProperty("timeout", 200);
 }
 //example of getting config from injected value
 //the program needs to update the injected value when batch is changed in Apollo using @ApolloConfigChangeListener shown above
 public int getBatch() {
 return this.batch;
 }

 private static class JsonBean{
 private String someString;
 private int someInt;
 }
}

在Configuration類中按照下面的方式使用:

@Configuration
@EnableApolloConfig
public class AppConfig {
 @Bean
 public TestApolloAnnotationBean testApolloAnnotationBean() {
 return new TestApolloAnnotationBean();
 }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末背亥,一起剝皮案震驚了整個(gè)濱河市秒际,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌狡汉,老刑警劉巖娄徊,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異盾戴,居然都是意外死亡寄锐,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來橄仆,“玉大人剩膘,你說我怎么就攤上這事∨韫耍” “怎么了怠褐?”我有些...
    開封第一講書人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)您宪。 經(jīng)常有香客問我奈懒,道長(zhǎng),這世上最難降的妖魔是什么蚕涤? 我笑而不...
    開封第一講書人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任筐赔,我火速辦了婚禮,結(jié)果婚禮上揖铜,老公的妹妹穿的比我還像新娘茴丰。我一直安慰自己,他們只是感情好天吓,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開白布贿肩。 她就那樣靜靜地躺著,像睡著了一般龄寞。 火紅的嫁衣襯著肌膚如雪汰规。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,749評(píng)論 1 289
  • 那天物邑,我揣著相機(jī)與錄音溜哮,去河邊找鬼。 笑死色解,一個(gè)胖子當(dāng)著我的面吹牛茂嗓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播科阎,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼述吸,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了锣笨?” 一聲冷哼從身側(cè)響起蝌矛,我...
    開封第一講書人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎错英,沒想到半個(gè)月后入撒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡椭岩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年衅金,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了噪伊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片簿煌。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡氮唯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出姨伟,到底是詐尸還是另有隱情惩琉,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布夺荒,位于F島的核電站瞒渠,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏技扼。R本人自食惡果不足惜伍玖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望剿吻。 院中可真熱鬧窍箍,春花似錦、人聲如沸丽旅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽榄笙。三九已至邪狞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間茅撞,已是汗流浹背帆卓。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留米丘,地道東北人剑令。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蠕蚜,于是被迫代替她去往敵國(guó)和親尚洽。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容