0%

springCloudConfig获取远程配置

springCloudConfig获取远程配置

springCloudConfig核心其实在于实现了一个PropertySourceLocator接口来进行获取远程配置的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
@Order(0)
public class ConfigServicePropertySourceLocator implements PropertySourceLocator {

@Override
@Retryable(interceptor = "configServerRetryInterceptor")
public org.springframework.core.env.PropertySource<?> locate(
org.springframework.core.env.Environment environment) {
ConfigClientProperties properties = this.defaultProperties.override(environment);
CompositePropertySource composite = new OriginTrackedCompositePropertySource(
"configService");
RestTemplate restTemplate = this.restTemplate == null
? getSecureRestTemplate(properties) : this.restTemplate;
Exception error = null;
String errorBody = null;
try {
String[] labels = new String[] { "" };
if (StringUtils.hasText(properties.getLabel())) {
labels = StringUtils
.commaDelimitedListToStringArray(properties.getLabel());
}
String state = ConfigClientStateHolder.getState();
// Try all the labels until one works
for (String label : labels) {
// 获取远程配置
Environment result = getRemoteEnvironment(restTemplate, properties,
label.trim(), state);
if (result != null) {
log(result);

// result.getPropertySources() can be null if using xml
if (result.getPropertySources() != null) {
for (PropertySource source : result.getPropertySources()) {
@SuppressWarnings("unchecked")
Map<String, Object> map = translateOrigins(source.getName(),
(Map<String, Object>) source.getSource());
composite.addPropertySource(
new OriginTrackedMapPropertySource(source.getName(),
map));
}
}

if (StringUtils.hasText(result.getState())
|| StringUtils.hasText(result.getVersion())) {
HashMap<String, Object> map = new HashMap<>();
putValue(map, "config.client.state", result.getState());
putValue(map, "config.client.version", result.getVersion());
composite.addFirstPropertySource(
new MapPropertySource("configClient", map));
}
return composite;
}
}
errorBody = String.format("None of labels %s found", Arrays.toString(labels));
}
catch (HttpServerErrorException e) {
error = e;
if (MediaType.APPLICATION_JSON
.includes(e.getResponseHeaders().getContentType())) {
errorBody = e.getResponseBodyAsString();
}
}
catch (Exception e) {
error = e;
}
if (properties.isFailFast()) {
throw new IllegalStateException(
"Could not locate PropertySource and the fail fast property is set, failing"
+ (errorBody == null ? "" : ": " + errorBody),
error);
}
logger.warn("Could not locate PropertySource: "
+ (error != null ? error.getMessage() : errorBody));
return null;

}

}

那么PropertySourceLocator接口是何时被调用的呢?

在springBoot启动的时候执行SpringApplication构造器的时候设置了ApplicationListener监听器

1
2
3
4
5
6
7
8
9
10
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 设置ApplicationListener监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}

其中监听器中有BootstrapApplicationListener,在该监听器中会加入一个ApplicationContextInitializer初始化器的实现类PropertySourceBootstrapConfiguration

1
2
3
Set target = new LinkedHashSet<>(application.getInitializers());
target.addAll(
getOrderedBeansOfType(context, ApplicationContextInitializer.class));

而在applyInitializers(context)中会遍历initializers初始化器集合,调用initialize方法

1
2
3
4
5
6
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}

在PropertySourceBootstrapConfiguration的initialize方法中会遍历propertySourceLocators集合,来执行PropertySourceLocator的locateCollection方法,这样就和springCloudConfig获取配置接上了,使用ConfigServicePropertySourceLocator类