Further paring down of leaky proeprty sources in Bootstrap phase
The biggest problem addressed here is one where an EnvironmentPostProcessor (reasonably) adds entries to the defaultProperties in the bootstrap context, but then that property source is not merged with the parent, or is merged too late (because it only happens when the application context parent is set). The result would be that things that were activated during bootstrap would be not be activated in the main context, or would be activated too late (early enough for beans to bind to but not for other listeners and post processors to get access to the additional properties). See https://github.com/spring-cloud/spring-cloud-sleuth/issues/126
This commit is contained in:
@@ -108,8 +108,9 @@ public class BootstrapApplicationListener
|
||||
// TODO: is it possible or sensible to share a ResourceLoader?
|
||||
SpringApplicationBuilder builder = new SpringApplicationBuilder()
|
||||
.profiles(environment.getActiveProfiles()).bannerMode(Mode.OFF)
|
||||
.environment(bootstrapEnvironment).registerShutdownHook(false)
|
||||
.properties("spring.application.name:" + configName).web(false);
|
||||
.environment(bootstrapEnvironment)
|
||||
.properties("spring.application.name:" + configName)
|
||||
.registerShutdownHook(false).web(false);
|
||||
List<Class<?>> sources = new ArrayList<>();
|
||||
for (String name : names) {
|
||||
Class<?> cls = ClassUtils.resolveClassName(name, null);
|
||||
@@ -129,9 +130,45 @@ public class BootstrapApplicationListener
|
||||
// It only has properties in it now that we don't want in the parent so remove
|
||||
// it (and it will be added back later)
|
||||
bootstrapProperties.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME);
|
||||
mergeDefaultProperties(environment.getPropertySources(), bootstrapProperties);
|
||||
return context;
|
||||
}
|
||||
|
||||
private void mergeDefaultProperties(MutablePropertySources environment,
|
||||
MutablePropertySources bootstrap) {
|
||||
String name = "defaultProperties";
|
||||
if (!bootstrap.contains(name)) {
|
||||
return;
|
||||
}
|
||||
PropertySource<?> source = bootstrap.get(name);
|
||||
if (source instanceof MapPropertySource) {
|
||||
Map<String, Object> map = ((MapPropertySource) source).getSource();
|
||||
// The application name is "bootstrap" (by default) at this point and
|
||||
// we don't want that to appear in the parent context at all.
|
||||
map.remove("spring.application.name");
|
||||
}
|
||||
if (!environment.contains(name)) {
|
||||
environment.addLast(source);
|
||||
}
|
||||
else {
|
||||
PropertySource<?> target = environment.get(name);
|
||||
if (target instanceof MapPropertySource) {
|
||||
Map<String, Object> targetMap = ((MapPropertySource) target).getSource();
|
||||
if (target == source) {
|
||||
return;
|
||||
}
|
||||
if (source instanceof MapPropertySource) {
|
||||
Map<String, Object> map = ((MapPropertySource) source).getSource();
|
||||
for (String key : map.keySet()) {
|
||||
if (!target.containsProperty(key)) {
|
||||
targetMap.put(key, map.get(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addAncestorInitializer(SpringApplication application,
|
||||
ConfigurableApplicationContext context) {
|
||||
boolean installed = false;
|
||||
|
||||
@@ -212,9 +212,9 @@ public class BootstrapConfigurationTests {
|
||||
.sources(BareConfiguration.class).run();
|
||||
assertEquals("main",
|
||||
this.context.getEnvironment().getProperty("spring.application.name"));
|
||||
// The parent is called "application" because spring.application.name is not
|
||||
// The parent has no name because spring.application.name is not
|
||||
// defined in the bootstrap properties
|
||||
assertEquals("application", this.context.getParent().getEnvironment()
|
||||
assertEquals(null, this.context.getParent().getEnvironment()
|
||||
.getProperty("spring.application.name"));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user