apollo和spring完美結合,自動更新估計也是反射,用起來非常舒服,推薦使用
spring的@value 初始化在下面的代碼裏
初始化 @value
SpringApplication
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
this.postProcessApplicationContext(context);
this.applyInitializers(context);
this.applyInitializers(context);
跟進去可以看見ApolloApplicationContextInitializer
this.initializers = {ArrayList@3947} size = 7
0 = {DelegatingApplicationContextInitializer@3957}
1 = {SharedMetadataReaderFactoryContextInitializer@3958}
2 = {ApolloApplicationContextInitializer@3959} --------------------- 這裏會把properSource設置入spring
3 = {ContextIdApplicationContextInitializer@3960}
4 = {ConfigurationWarningsApplicationContextInitializer@3961}
5 = {ServerPortInfoApplicationContextInitializer@3962}
6 = {ConditionEvaluationReportLoggingListener@3963}
然後這個ApolloApplicationContextInitializer的initialize方法如下
public void initialize(ConfigurableApplicationContext context) {
ConfigurableEnvironment environment = context.getEnvironment();
String enabled = environment.getProperty("apollo.bootstrap.enabled", "false");
if (!Boolean.valueOf(enabled)) {
logger.debug("Apollo bootstrap config is not enabled for context {}, see property: ${{}}", context, "apollo.bootstrap.enabled");
} else {
logger.debug("Apollo bootstrap config is enabled for context {}", context);
this.initialize(environment);
}
}
上面方法裏還有這一步environment.getPropertySources().addFirst(composite);將property設置入environment第一個
從這一步起Config config = ConfigService.getConfig(namespace);
經過一系列的操作 如下等等
return new DefaultConfig(namespace, createLocalConfigRepository(namespace));
最終進入這個方法return new RemoteConfigRepository(namespace);這是個關鍵類
apollo先隨便理理,以後再補充吧
關鍵類是這個RemoteConfigRepository
關鍵代碼是這幾步驟
this.trySync();// 嘗試同步配置
this.schedulePeriodicRefresh();// 初始化定時刷新配置的任務
this.scheduleLongPollingRefresh();// 註冊自己到 RemoteConfigLongPollService 中,實現配置更新的實時通知
-------------------------------------------------------------------
trySync裏面有個關鍵代碼
ApolloConfig current = loadApolloConfig();
裏面調接口
url = assembleQueryConfigUrl(configService.getHomepageUrl(), appId, cluster, m_namespace,
dataCenter, m_remoteMessages.get(), m_configCache.get());
HttpResponse<ApolloConfig> response = m_httpUtil.doGet(request, ApolloConfig.class);
get獲取
HttpResponse<ApolloConfig> response = m_httpUtil.doGet(request, ApolloConfig.class);
其中的url類似這個
http://localhost:8080/configs/test_1/default/application.properties?ip=localhost
返回類似這個 裏面已經有我設置好的值了
{
"appId": "test_1",
"cluster": "default",
"namespaceName": "application.properties",
"configurations": {
"apollo.property1": "xxx",
"apollo.percent": "444"
},
"releaseKey": "20191011143416-fe52624c5bd4583f"
}
獲取的返回就是一個AplloConfig
ApolloConfig result = response.getBody();
然後設置入
m_configCache.set(current);
this.remoteConfigLongPollService.submit(this.m_namespace, this);
------------------------------------------------------------------------------
this.schedulePeriodicRefresh(); 這個定時更新就是默認每5分鐘更新下trySync一下
---------------------------------------------------------------------------
this.scheduleLongPollingRefresh();這裏是個長連接更新 經過下面一系列的方法
remoteConfigLongPollService.submit(m_namespace, this);
startLongPolling();
進入關鍵的一步
m_longPollingService.submit(new Runnable() {
@Override
public void run() {
if (longPollingInitialDelayInMills > 0) {
try {
logger.debug("Long polling will start in {} ms.", longPollingInitialDelayInMills);
TimeUnit.MILLISECONDS.sleep(longPollingInitialDelayInMills);
} catch (InterruptedException e) {
//ignore
}
}
doLongPollingRefresh(appId, cluster, dataCenter);
}
});
默認睡2秒 執行這個
doLongPollingRefresh(appId, cluster, dataCenter);
裏面進去就是個死循環
while (!m_longPollingStopped.get() && !Thread.currentThread().isInterrupted()) {
裏面又是個get請求
url =
assembleLongPollRefreshUrl(lastServiceDto.getHomepageUrl(), appId, cluster, dataCenter,
m_notifications);
url類似這個
http://localhost:8080/notifications/v2?cluster=default&appId=test_1&ip=localhost¬ifications=%5B%7B%22namespaceName%22%3A%22application.properties%22%2C%22notificationId%22%3A-1%7D%5D
response類似這個
[{
"namespaceName": "application",
"notificationId": 26,
"messages": {
"details": {
"test_1+default+application": 26
}
}
}]
根據返回值在進行操作 如果有改變 返回值就是200
if (response.getStatusCode() == 200 && response.getBody() != null) {
updateNotifications(response.getBody());
updateRemoteNotifications(response.getBody());
transaction.addData("Result", response.getBody().toString());
notify(lastServiceDto, response.getBody());
}
notify(lastServiceDto, response.getBody());這一步裏面還有trySync操作 更新上面的RemoteConfigRepository
而且這裏面有個比較詭異的點 在死循環中 如果apollo服務端沒有更新的notification,客戶端調用如下網址,就會超時,默認90s
估計是服務端做了控制,雖然是長連接,但是如果沒有notification,還空轉的話,對客戶端服務端都不好,自己猜的
好,綜上就是apollo能注入@value,且能及時更新的原因了,標紅爲關鍵部分
寫的比較糙,自己看的