Spring Cloud Config 源码分析
今天我们来分析一下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
共同学习,写下你的评论
评论加载中...
作者其他优质文章