apollo spring @value 源码分析

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&notifications=%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

http://localhost:8080/notifications/v2?cluster=default&appId=test_1&ip=localhost&notifications=%5B%7B"namespaceName"%3A"application.properties"%2C"notificationId"%3A29%7D%2C%7B"namespaceName"%3A"application"%2C"notificationId"%3A29%7D%5D

估计是服务端做了控制,虽然是长连接,但是如果没有notification,还空转的话,对客户端服务端都不好,自己猜的

好,综上就是apollo能注入@value,且能及时更新的原因了,标红为关键部分

写的比较糙,自己看的

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值