客戶端獲取Namespace配置
默認的namespace配置獲取
Config config = ConfigService.getAppConfig();
Integer defaultRequestTimeout = 200;
Integer requestTimeout = config.getIntProperty("requestTimeout", defaultRequestTimeout);
自定義namespace的配置獲取
Config config = ConfigService.getConfig("FX.Hermes.Producer");
Integer defaultSenderBatchSize = 200;
Integer senderBatchSize = config.getIntProperty("sender.batchsize", defaultSenderBatchSize);
客戶端監(jiān)聽Namespace配置變化
默認的namespace配置的監(jiān)聽
Config config = ConfigService.getAppConfig();
config.addChangeListener(new ConfigChangeListener() {
@Override
public void onChange(ConfigChangeEvent changeEvent) {
for (String key : changeEvent.changedKeys()) {
ConfigChange change = changeEvent.getChange(key);
System.out.println(String.format(
"Found change - key: %s, oldValue: %s, newValue: %s, changeType: %s",
change.getPropertyName(), change.getOldValue(),
change.getNewValue(), change.getChangeType()));
}
}
});
自定義namespace配置的監(jiān)聽
Config config = ConfigService.getConfig("FX.Hermes.Producer");
config.addChangeListener(new ConfigChangeListener() {
@Override
public void onChange(ConfigChangeEvent changeEvent) {
System.out.println("Changes for namespace " + changeEvent.getNamespace());
for (String key : changeEvent.changedKeys()) {
ConfigChange change = changeEvent.getChange(key);
System.out.println(String.format(
"Found change - key: %s, oldValue: %s, newValue: %s, changeType: %s",
change.getPropertyName(), change.getOldValue(),
change.getNewValue(), change.getChangeType()));
}
}
});
Spring集成樣例
Apollo和Spring也可以很方便地集成,只需要標注@EnableApolloConfig后就可以通過@Value獲取配置信息:
@Configuration
@EnableApolloConfig
public class AppConfig {}
-------------------------------------------------------------------------------------
@Component
public class SomeBean {
@Value("${request.timeout:200}")
private int timeout;
@ApolloConfigChangeListener
private void someChangeHandler(ConfigChangeEvent changeEvent) {
if (changeEvent.isChanged("request.timeout")) {
refreshTimeout();
}
}
}
-------------------------------------------------------------------------------------
@Configuration
@EnableApolloConfig("FX.Hermes.Producer")
public class AppConfig {}
-------------------------------------------------------------------------------------
@Component
public class SomeBean {
@Value("${request.timeout:200}")
private int timeout;
@ApolloConfigChangeListener("FX.Hermes.Producer")
private void someChangeHandler(ConfigChangeEvent changeEvent) {
if (changeEvent.isChanged("request.timeout")) {
refreshTimeout();
}
}
}
應(yīng)用自身配置的獲取規(guī)則(namespace=default)
??當應(yīng)用使用下面的語句獲取配置時,我們稱之為獲取應(yīng)用自身的配置掉盅,也就是應(yīng)用自身的application namespace的配置搜囱。
Config config = ConfigService.getAppConfig();
對這種情況的配置獲取規(guī)則,簡而言之如下:
- 首先查找運行時cluster的配置(通過apollo.cluster指定)
- 如果沒有找到甫恩,則查找數(shù)據(jù)中心cluster的配置
- 如果還是沒有找到逆济,則返回默認cluster的配置
??所以如果應(yīng)用部署在A數(shù)據(jù)中心,但是用戶沒有在Apollo創(chuàng)建cluster磺箕,那么獲取的配置就是默認cluster(default)的奖慌。
??如果應(yīng)用部署在A數(shù)據(jù)中心,同時在運行時指定了SomeCluster松靡,但是沒有在Apollo創(chuàng)建cluster简僧,那么獲取的配置就是A數(shù)據(jù)中心cluster的配置,如果A數(shù)據(jù)中心cluster沒有配置的話雕欺,那么獲取的配置就是默認cluster(default)的岛马。
公共組件配置的獲取規(guī)則
??以FX.Hermes.Producer為例,hermes producer是hermes發(fā)布的公共組件屠列。當使用下面的語句獲取配置時啦逆,我們稱之為獲取公共組件的配置。
Config config = ConfigService.getConfig("FX.Hermes.Producer");
對這種情況的配置獲取規(guī)則笛洛,簡而言之如下:
- 首先獲取當前應(yīng)用下的FX.Hermes.Producer namespace的配置
- 然后獲取hermes應(yīng)用下FX.Hermes.Producer namespace的配置
-
上面兩部分配置的并集就是最終使用的配置夏志,如有key一樣的部分,以當前應(yīng)用優(yōu)先
配置查找順序
??通過這種方式苛让,就實現(xiàn)了對框架類組件的配置管理沟蔑,框架組件提供方提供配置的默認值湿诊,應(yīng)用如果有特殊需求,可以自行覆蓋瘦材。
配置更新推送實現(xiàn)
??前面提到了Apollo客戶端和服務(wù)端保持了一個長連接枫吧,從而能第一時間獲得配置更新的推送。長連接實際上我們是通過Http Long Polling實現(xiàn)的宇色,具體而言:
- 客戶端發(fā)起一個Http請求到服務(wù)端
- 服務(wù)端會保持住這個連接30秒
- 如果在30秒內(nèi)有客戶端關(guān)心的配置變化九杂,被保持住的客戶端請求會立即返回,并告知客戶端有配置變化的namespace信息宣蠕,客戶端會據(jù)此拉取對應(yīng)namespace的最新配置
- 如果在30秒內(nèi)沒有客戶端關(guān)心的配置變化例隆,那么會返回Http狀態(tài)碼304給客戶端
- 客戶端在收到服務(wù)端請求后會立即重新發(fā)起連接,回到第一步
??考慮到會有數(shù)萬客戶端向服務(wù)端發(fā)起長連抢蚀,在服務(wù)端我們使用了async servlet(Spring DeferredResult)來服務(wù)Http Long Polling請求镀层。