为了账号安全,请及时绑定邮箱和手机立即绑定

Spring Cloud Config 源码分析

标签:
Spring Cloud

今天我们来分析一下spring cloud 的 config 的源码。我们可以看到spring-cloud-config-client项目下的spring.factories文件中定义了我们今天所要讲的文 ConfigClientAutoConfiguration 与ConfigServiceBootstrapConfiguration。他们被自动引入进我们的容器中作为Bean。我们先看一下ConfigServiceBootstrapConfiguration

@Configuration@EnableConfigurationPropertiespublic class ConfigServiceBootstrapConfiguration {   @Autowired
   private ConfigurableEnvironment environment;

   ...   @Bean
   @ConditionalOnProperty(value = "spring.cloud.config.enabled", matchIfMissing = true)   public ConfigServicePropertySourceLocator configServicePropertySource() {
      ConfigServicePropertySourceLocator locator = new ConfigServicePropertySourceLocator(
            configClientProperties());      return locator;
   }

   ...

}

我们说一下作为重要的一个Bean configServicePropertySource,他的作用就是从远程服务器上拿到我们的配置,放入到spring 容器中的
environment 中。让我们详细的看一下。

@Override
@Retryable(interceptor = "configServerRetryInterceptor")
public org.springframework.core.env.PropertySource<?> locate(
      org.springframework.core.env.Environment environment) {
   ConfigClientProperties client = this.defaults.override(environment);
   CompositePropertySource composite = new CompositePropertySource("configService");
   RestTemplate restTemplate = this.restTemplate == null ? getSecureRestTemplate(client)
         : this.restTemplate;
   Exception error = null;   String errorBody = null;
   logger.info("Fetching config from server at: " + client.getRawUri());   try {      String[] labels = new String[]{""};      if (StringUtils.hasText(client.getLabel())) {
         labels = StringUtils.commaDelimitedListToStringArray(client.getLabel());
      }      // Try all the labels until one works
      for (String label : labels) {
         Environment result = getRemoteEnvironment(restTemplate, client.getRawUri(), client.getName(), client.getProfile(), label.trim());         if (result != null) {
            logger.info(String.format("Located environment: name=%s, profiles=%s, label=%s, version=%s",
                  result.getName(),
                  result.getProfiles() == null ? "" : Arrays.asList(result.getProfiles()),
                  result.getLabel(), result.getVersion()));            for (PropertySource source : result.getPropertySources()) {
               @SuppressWarnings("unchecked")               Map<String, Object> map = (Map<String, Object>) source
                     .getSource();
               composite.addPropertySource(new MapPropertySource(source
                     .getName(), map));
            }            return composite;
         }
      }
   }   catch (HttpServerErrorException e) {
      error = e;      if (MediaType.APPLICATION_JSON.includes(e.getResponseHeaders()
            .getContentType())) {
         errorBody = e.getResponseBodyAsString();
      }
   }   catch (Exception e) {
      error = e;
   }   if (client != null && client.isFailFast()) {      throw new IllegalStateException(            "Could not locate PropertySource and the fail fast property is set, failing",
            error);
   }
   logger.warn("Could not locate PropertySource: "
         + (errorBody == null ? error==null ? "label not found" : error.getMessage() : errorBody));   return null;

}
 
 
private Environment getRemoteEnvironment(RestTemplate restTemplate, String uri, String name, String profile, String label) {   String path = "/{name}/{profile}";   Object[] args = new String[] { name, profile };   if (StringUtils.hasText(label)) {
      args = new String[] { name, profile, label };
      path = path + "/{label}";
   }
   ResponseEntity<Environment> response = null;   try {
      response = restTemplate.exchange(uri + path,
            HttpMethod.GET, new HttpEntity<Void>((Void) null),
            Environment.class, args);
   } catch (HttpClientErrorException e) {      if(e.getStatusCode() != HttpStatus.NOT_FOUND ) {         throw e;
      }
   }   if (response==null || response.getStatusCode()!=HttpStatus.OK) {      return null;
   }
   Environment result = response.getBody();   return result;
}

这个类的生命周期方法是locate,getRemoteEnvironment这个方法就是从远程服务器上拉取数据,将数据放入到Environment中返回,然后解析得到的Environment,将数据放入
composite。在哪里用呢?请看PropertySourceBootstrapConfiguration

@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {
   CompositePropertySource composite = new CompositePropertySource(
         BOOTSTRAP_PROPERTY_SOURCE_NAME);
   AnnotationAwareOrderComparator.sort(this.propertySourceLocators);   boolean empty = true;
   ConfigurableEnvironment environment = applicationContext.getEnvironment();   for (PropertySourceLocator locator : this.propertySourceLocators) {
      PropertySource<?> source = null;
      source = locator.locate(environment);      if (source == null) {         continue;
      }
      logger.info("Located property source: " + source);
      composite.addPropertySource(source);
      empty = false;
   }   if (!empty) {
      MutablePropertySources propertySources = environment.getPropertySources();
      String logConfig = environment.resolvePlaceholders("${logging.config:}");
      LogFile logFile = LogFile.get(environment);      if (propertySources.contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
         propertySources.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME);
      }
      insertPropertySources(propertySources, composite);
      reinitializeLoggingSystem(environment, logConfig, logFile);
      setLogLevels(environment);
   }
}

首先这是一个ApplicationContextInitializer的子类,那么会在spring boot 进行初始化的时候调用,将所有PropertySourceLocator类型的对象的locate方法都调用一遍,然后将各个渠道得到的属性值放到
composite中利用insertPropertySources(propertySources, composite)设置到environment中,这样容器就得到了。



作者:数齐
链接:https://www.jianshu.com/p/725cf81b07f9


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
205
获赞与收藏
1007

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消