Change handling of spring.config.location so it replaces defaults

Previously, spring.config.name was handled in such a way that its
value would replace the defaults. By constrast, spring.config.location
would add to the defaults.

Update the handling of spring.config.location so that it replaces the
defaults. This aligns its behaviour with spring.config.name. To allow
users to add additional locations a new property,
spring.config.additional-location, has been introduced. It behaves as
spring.config.location did prior to this change.

Closes gh-10595
This commit is contained in:
Andy Wilkinson 2017-10-28 12:33:52 +01:00
parent 9b8fefb0f4
commit 8eae372433
4 changed files with 99 additions and 14 deletions

View File

@ -555,17 +555,27 @@ before being loaded, including profile-specific file names). Files specified in
and are overridden by any profile-specific properties.
Config locations are searched in reverse order. By default, the configured locations are
`classpath:/,classpath:/config/,file:./,file:./config/`. The resulting search order is:
`classpath:/,classpath:/config/,file:./,file:./config/`. The resulting search order is the
following:
. `file:./config/`
. `file:./`
. `classpath:/config/`
. `classpath:/`
When custom config locations are configured, they are used in addition to the default
locations. Custom locations are searched before the default locations. For example, if
custom locations of `classpath:/custom-config/,file:./custom-config/` are configured, the
search order becomes:
When custom config locations are configured using `spring.config.location` they replace
the default locations. For example, if `spring.config.location` is configured with the
value `classpath:/custom-config/,file:./custom-config/`, the search order becomes the
following:
. `file:./custom-config/`
. `classpath:custom-config/`
Alternatively, when custom config locations are configured using
`spring.config.addition-location`, they are used in addition to the default locations.
Additional locations are search before the default locations. For example, if
additional locations of `classpath:/custom-config/,file:./custom-config/` are configured,
the search order becomes the following:
. `file:./custom-config/`
. `classpath:custom-config/`

View File

@ -121,6 +121,11 @@ public class ConfigFileApplicationListener
*/
public static final String CONFIG_LOCATION_PROPERTY = "spring.config.location";
/**
* The "config additional location" property name.
*/
public static final String CONFIG_ADDITIONAL_LOCATION_PROPERTY = "spring.config.additional-location";
/**
* The default order for the processor.
*/
@ -563,11 +568,22 @@ public class ConfigFileApplicationListener
}
private Set<String> getSearchLocations() {
Set<String> locations = new LinkedHashSet<>();
// User-configured settings take precedence, so we do them first
if (this.environment.containsProperty(CONFIG_LOCATION_PROPERTY)) {
return getSearchLocations(CONFIG_LOCATION_PROPERTY);
}
Set<String> locations = getSearchLocations(
CONFIG_ADDITIONAL_LOCATION_PROPERTY);
locations.addAll(
asResolvedSet(ConfigFileApplicationListener.this.searchLocations,
DEFAULT_SEARCH_LOCATIONS));
return locations;
}
private Set<String> getSearchLocations(String propertyName) {
Set<String> locations = new LinkedHashSet<>();
if (this.environment.containsProperty(propertyName)) {
for (String path : asResolvedSet(
this.environment.getProperty(CONFIG_LOCATION_PROPERTY), null)) {
this.environment.getProperty(propertyName), null)) {
if (!path.contains("$")) {
path = StringUtils.cleanPath(path);
if (!ResourceUtils.isUrl(path)) {
@ -577,9 +593,6 @@ public class ConfigFileApplicationListener
locations.add(path);
}
}
locations.addAll(
asResolvedSet(ConfigFileApplicationListener.this.searchLocations,
DEFAULT_SEARCH_LOCATIONS));
return locations;
}

View File

@ -132,6 +132,12 @@
"description": "Skip search of BeanInfo classes.",
"defaultValue": true
},
{
"name": "spring.config.additional-location",
"type": "java.lang.String",
"sourceType": "org.springframework.boot.context.config.ConfigFileApplicationListener",
"description": "Config file locations used in addition to the defaults."
},
{
"name": "spring.config.name",
"type": "java.lang.String",
@ -143,7 +149,7 @@
"name": "spring.config.location",
"type": "java.lang.String",
"sourceType": "org.springframework.boot.context.config.ConfigFileApplicationListener",
"description": "Config file locations."
"description": "Config file locations that replace the defaults."
},
{
"name": "spring.jta.atomikos.properties.console-log-level",

View File

@ -154,8 +154,20 @@ public class ConfigFileApplicationListenerTests {
@Test
public void loadTwoPropertiesFilesWithProfiles() throws Exception {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
"spring.config.location="
+ "classpath:enableprofile.properties,classpath:enableother.properties");
"spring.config.location=classpath:enableprofile.properties,"
+ "classpath:enableother.properties");
this.initializer.postProcessEnvironment(this.environment, this.application);
assertThat(this.environment.getActiveProfiles()).containsExactly("other");
String property = this.environment.getProperty("my.property");
assertThat(property).isEqualTo("fromenableotherpropertiesfile");
}
@Test
public void loadTwoPropertiesFilesWithProfilesUsingAdditionalLocation()
throws Exception {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
"spring.config.additional-location=classpath:enableprofile.properties,"
+ "classpath:enableother.properties");
this.initializer.postProcessEnvironment(this.environment, this.application);
assertThat(this.environment.getActiveProfiles()).containsExactly("other");
String property = this.environment.getProperty("my.property");
@ -564,6 +576,22 @@ public class ConfigFileApplicationListenerTests {
this.initializer.postProcessEnvironment(this.environment, this.application);
String property = this.environment.getProperty("the.property");
assertThat(property).isEqualTo("fromspecificlocation");
assertThat(this.environment).has(matchingPropertySource(
"applicationConfig: " + "[classpath:specificlocation.properties]"));
// The default property source is not there
assertThat(this.environment).doesNotHave(matchingPropertySource(
"applicationConfig: " + "[classpath:/application.properties]"));
assertThat(this.environment.getProperty("foo")).isNull();
}
@Test
public void specificResourceFromAdditionalLocation() throws Exception {
String additionalLocation = "classpath:specificlocation.properties";
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
"spring.config.additional-location=" + additionalLocation);
this.initializer.postProcessEnvironment(this.environment, this.application);
String property = this.environment.getProperty("the.property");
assertThat(property).isEqualTo("fromspecificlocation");
assertThat(this.environment).has(matchingPropertySource(
"applicationConfig: " + "[classpath:specificlocation.properties]"));
// The default property source is still there
@ -816,6 +844,34 @@ public class ConfigFileApplicationListenerTests {
.containsExactly("testPropertySource");
}
@Test
public void additionalLocationTakesPrecedenceOverDefaultLocation() throws Exception {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
"spring.config.additional-location=classpath:override.properties");
this.initializer.postProcessEnvironment(this.environment, this.application);
assertThat(this.environment.getProperty("foo")).isEqualTo("bar");
assertThat(this.environment.getProperty("value")).isEqualTo("1234");
}
@Test
public void lastAdditionalLocationWins() throws Exception {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
"spring.config.additional-location=classpath:override.properties,"
+ "classpath:some.properties");
this.initializer.postProcessEnvironment(this.environment, this.application);
assertThat(this.environment.getProperty("foo")).isEqualTo("spam");
assertThat(this.environment.getProperty("value")).isEqualTo("1234");
}
@Test
public void locationReplaceDefaultLocation() throws Exception {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
"spring.config.location=classpath:override.properties");
this.initializer.postProcessEnvironment(this.environment, this.application);
assertThat(this.environment.getProperty("foo")).isEqualTo("bar");
assertThat(this.environment.getProperty("value")).isNull();
}
private Condition<ConfigurableEnvironment> matchingPropertySource(
final String sourceName) {
return new Condition<ConfigurableEnvironment>(