Adjust order of property sources

@PropertySources *can* and should be added in the slot
after the application.properties (code that is part of the
application should have lower precedence than external
configuration).

Fixes gh-1044
This commit is contained in:
Dave Syer 2014-06-07 08:52:50 +01:00
parent e81e94924c
commit b75578d99c
11 changed files with 62 additions and 32 deletions

View File

@ -207,11 +207,11 @@ sensible overriding of values, properties are considered in the the following or
. OS environment variables.
. JNDI attributes from `java:comp/env`
. A `RandomValuePropertySource` that only has properties in `random.*`.
. `@PropertySource` annotations on your `@Configuration` classes.
. Application properties outside of your packaged jar (`application.properties`
including YAML and profile variants).
. Application properties packaged inside your jar (`application.properties`
including YAML and profile variants).
. `@PropertySource` annotations on your `@Configuration` classes.
. Default properties (specified using `SpringApplication.setDefaultProperties`).
To provide a concrete example, suppose you develop a `@Component` that uses a

View File

@ -497,19 +497,22 @@ public class ConfigFileApplicationListener implements
public static void finishAndRelocate(MutablePropertySources propertySources) {
ConfigurationPropertySources removed = (ConfigurationPropertySources) propertySources
.remove(ConfigurationPropertySources.NAME);
.get(ConfigurationPropertySources.NAME);
String name = ConfigurationPropertySources.NAME;
if (removed != null) {
for (PropertySource<?> propertySource : removed.sources) {
if (propertySource instanceof EnumerableCompositePropertySource) {
EnumerableCompositePropertySource composite = (EnumerableCompositePropertySource) propertySource;
for (PropertySource<?> nested : composite.getSource()) {
propertySources.addLast(nested);
propertySources.addAfter(name, nested);
name = nested.getName();
}
}
else {
propertySources.addLast(propertySource);
propertySources.addAfter(name, propertySource);
}
}
propertySources.remove(ConfigurationPropertySources.NAME);
}
}

View File

@ -53,13 +53,23 @@ public class PropertySourcesBindingTests {
private Wrapper properties;
@Test
public void overridingOfPropertiesWorksAsExpected() {
public void overridingOfPropertiesOrderOfAtPropertySources() {
assertThat(this.properties.getBar(), is("override"));
}
@Test
public void overridingOfPropertiesAndBindToAtValue() {
assertThat(this.foo, is(this.properties.getFoo()));
}
@Test
public void overridingOfPropertiesOrderOfApplicationProperties() {
assertThat(this.properties.getFoo(), is("bucket"));
}
@Import({ SomeConfig.class })
@PropertySources({ @PropertySource("classpath:/override.properties"),
@PropertySource("classpath:/some.properties") })
@PropertySources({ @PropertySource("classpath:/some.properties"),
@PropertySource("classpath:/override.properties") })
@Configuration
@EnableConfigurationProperties(Wrapper.class)
public static class TestConfig {
@ -81,6 +91,16 @@ public class PropertySourcesBindingTests {
public static class Wrapper {
private String foo;
private String bar;
public String getBar() {
return this.bar;
}
public void setBar(String bar) {
this.bar = bar;
}
public String getFoo() {
return this.foo;
}

View File

@ -82,7 +82,7 @@ public class ConfigFileApplicationListenerTests {
@After
public void cleanup() {
System.clearProperty("my.property");
System.clearProperty("the.property");
System.clearProperty("spring.config.location");
System.clearProperty("spring.main.showBanner");
}
@ -93,7 +93,7 @@ public class ConfigFileApplicationListenerTests {
@Override
public Resource getResource(final String location) {
if (location.equals("classpath:/custom.properties")) {
return new ByteArrayResource("my.property: fromcustom".getBytes(),
return new ByteArrayResource("the.property: fromcustom".getBytes(),
location) {
@Override
public String getFilename() {
@ -111,7 +111,7 @@ public class ConfigFileApplicationListenerTests {
});
this.initializer.setSearchNames("custom");
this.initializer.onApplicationEvent(this.event);
String property = this.environment.getProperty("my.property");
String property = this.environment.getProperty("the.property");
assertThat(property, equalTo("fromcustom"));
}
@ -119,7 +119,7 @@ public class ConfigFileApplicationListenerTests {
public void loadPropertiesFile() throws Exception {
this.initializer.setSearchNames("testproperties");
this.initializer.onApplicationEvent(this.event);
String property = this.environment.getProperty("my.property");
String property = this.environment.getProperty("the.property");
assertThat(property, equalTo("frompropertiesfile"));
}
@ -128,7 +128,7 @@ public class ConfigFileApplicationListenerTests {
EnvironmentTestUtils.addEnvironment(this.environment, "spring.config.location:"
+ "classpath:application.properties,classpath:testproperties.properties");
this.initializer.onApplicationEvent(this.event);
String property = this.environment.getProperty("my.property");
String property = this.environment.getProperty("the.property");
assertThat(property, equalTo("frompropertiesfile"));
}
@ -152,7 +152,7 @@ public class ConfigFileApplicationListenerTests {
assertEquals("myprofile",
StringUtils.arrayToCommaDelimitedString(this.environment
.getActiveProfiles()));
String property = this.environment.getProperty("my.property");
String property = this.environment.getProperty("the.property");
// The value from the second file wins (no profile specific configuration is
// actually loaded)
assertThat(property, equalTo("frompropertiesfile"));
@ -168,7 +168,7 @@ public class ConfigFileApplicationListenerTests {
assertEquals("myprofile",
StringUtils.arrayToCommaDelimitedString(this.environment
.getActiveProfiles()));
String property = this.environment.getProperty("my.property");
String property = this.environment.getProperty("the.property");
// The value from the second file wins (no profile specific configuration is
// actually loaded)
assertThat(property, equalTo("frompropertiesfile"));
@ -180,7 +180,7 @@ public class ConfigFileApplicationListenerTests {
assertThat(localFile.exists(), equalTo(false));
try {
Properties properties = new Properties();
properties.put("my.property", "fromlocalfile");
properties.put("the.property", "fromlocalfile");
OutputStream out = new FileOutputStream(localFile);
try {
properties.store(out, "");
@ -189,7 +189,7 @@ public class ConfigFileApplicationListenerTests {
out.close();
}
this.initializer.onApplicationEvent(this.event);
String property = this.environment.getProperty("my.property");
String property = this.environment.getProperty("the.property");
assertThat(property, equalTo("fromlocalfile"));
}
finally {
@ -213,7 +213,7 @@ public class ConfigFileApplicationListenerTests {
+ "classpath:testproperties.properties,"
+ "classpath:nonexistent.properties");
this.initializer.onApplicationEvent(this.event);
String property = this.environment.getProperty("my.property");
String property = this.environment.getProperty("the.property");
assertThat(property, equalTo("frompropertiesfile"));
}
@ -228,7 +228,7 @@ public class ConfigFileApplicationListenerTests {
public void loadTwoPropertiesFiles() throws Exception {
this.initializer.setSearchNames("moreproperties,testproperties");
this.initializer.onApplicationEvent(this.event);
String property = this.environment.getProperty("my.property");
String property = this.environment.getProperty("the.property");
// The search order has highest precedence last (like merging a map)
assertThat(property, equalTo("frompropertiesfile"));
}
@ -246,19 +246,19 @@ public class ConfigFileApplicationListenerTests {
@Test
public void commandLineWins() throws Exception {
this.environment.getPropertySources().addFirst(
new SimpleCommandLinePropertySource("--my.property=fromcommandline"));
new SimpleCommandLinePropertySource("--the.property=fromcommandline"));
this.initializer.setSearchNames("testproperties");
this.initializer.onApplicationEvent(this.event);
String property = this.environment.getProperty("my.property");
String property = this.environment.getProperty("the.property");
assertThat(property, equalTo("fromcommandline"));
}
@Test
public void systemPropertyWins() throws Exception {
System.setProperty("my.property", "fromsystem");
System.setProperty("the.property", "fromsystem");
this.initializer.setSearchNames("testproperties");
this.initializer.onApplicationEvent(this.event);
String property = this.environment.getProperty("my.property");
String property = this.environment.getProperty("the.property");
assertThat(property, equalTo("fromsystem"));
}
@ -285,7 +285,7 @@ public class ConfigFileApplicationListenerTests {
.singletonMap("spring.config.name",
(Object) "testproperties")));
this.initializer.onApplicationEvent(this.event);
String property = this.environment.getProperty("my.property");
String property = this.environment.getProperty("the.property");
assertThat(property, equalTo("frompropertiesfile"));
}
@ -318,7 +318,7 @@ public class ConfigFileApplicationListenerTests {
public void loadPropertiesThenProfilePropertiesActivatedInFirst() throws Exception {
this.initializer.setSearchNames("enableprofile");
this.initializer.onApplicationEvent(this.event);
String property = this.environment.getProperty("my.property");
String property = this.environment.getProperty("the.property");
// The "myprofile" profile is activated in enableprofile.properties so its value
// should show up here
assertThat(property, equalTo("fromprofilepropertiesfile"));
@ -334,7 +334,7 @@ public class ConfigFileApplicationListenerTests {
String property = this.environment.getProperty("other.property");
// The "other" profile is activated before any processing starts
assertThat(property, equalTo("fromotherpropertiesfile"));
property = this.environment.getProperty("my.property");
property = this.environment.getProperty("the.property");
// The "myprofile" profile is activated in enableprofile.properties and "other"
// was not activated by setting spring.profiles.active so "myprofile" should still
// be activated
@ -428,7 +428,7 @@ public class ConfigFileApplicationListenerTests {
EnvironmentTestUtils.addEnvironment(this.environment, "spring.config.location:"
+ location);
this.initializer.onApplicationEvent(this.event);
String property = this.environment.getProperty("my.property");
String property = this.environment.getProperty("the.property");
assertThat(property, equalTo("fromspecificlocation"));
assertThat(this.environment, containsPropertySource("applicationConfig: "
+ "[classpath:specificlocation.properties]"));
@ -463,7 +463,7 @@ public class ConfigFileApplicationListenerTests {
SpringApplication application = new SpringApplication(WithPropertySource.class);
application.setWebEnvironment(false);
ConfigurableApplicationContext context = application.run();
String property = context.getEnvironment().getProperty("my.property");
String property = context.getEnvironment().getProperty("the.property");
assertThat(property, equalTo("fromspecificlocation"));
assertThat(context.getEnvironment(),
containsPropertySource("class path resource "
@ -480,7 +480,7 @@ public class ConfigFileApplicationListenerTests {
application.setEnvironment(this.environment);
application.setWebEnvironment(false);
ConfigurableApplicationContext context = application.run();
String property = context.getEnvironment().getProperty("my.property");
String property = context.getEnvironment().getProperty("the.property");
assertThat(property, equalTo("fromspecificlocation"));
assertThat(context.getEnvironment(),
containsPropertySource("class path resource "
@ -494,7 +494,7 @@ public class ConfigFileApplicationListenerTests {
WithPropertySourceAndName.class);
application.setWebEnvironment(false);
ConfigurableApplicationContext context = application.run();
String property = context.getEnvironment().getProperty("my.property");
String property = context.getEnvironment().getProperty("the.property");
assertThat(property, equalTo("fromspecificlocation"));
assertThat(context.getEnvironment(), containsPropertySource("foo"));
context.close();
@ -507,7 +507,7 @@ public class ConfigFileApplicationListenerTests {
application.setWebEnvironment(false);
ConfigurableApplicationContext context = application
.run("--spring.profiles.active=myprofile");
String property = context.getEnvironment().getProperty("my.property");
String property = context.getEnvironment().getProperty("the.property");
assertThat(property, equalTo("frompropertiesfile"));
assertThat(context.getEnvironment(),
containsPropertySource("class path resource "
@ -536,7 +536,7 @@ public class ConfigFileApplicationListenerTests {
WithPropertySourceMultipleLocations.class);
application.setWebEnvironment(false);
ConfigurableApplicationContext context = application.run();
String property = context.getEnvironment().getProperty("my.property");
String property = context.getEnvironment().getProperty("the.property");
assertThat(property, equalTo("frommorepropertiesfile"));
assertThat(context.getEnvironment(),
containsPropertySource("class path resource "
@ -550,7 +550,7 @@ public class ConfigFileApplicationListenerTests {
WithPropertySourceMultipleLocationsAndName.class);
application.setWebEnvironment(false);
ConfigurableApplicationContext context = application.run();
String property = context.getEnvironment().getProperty("my.property");
String property = context.getEnvironment().getProperty("the.property");
assertThat(property, equalTo("frommorepropertiesfile"));
assertThat(context.getEnvironment(), containsPropertySource("foo"));
context.close();

View File

@ -1 +1,2 @@
my.property=fromprofilepropertiesfile
the.property=fromprofilepropertiesfile

View File

@ -1,3 +1,4 @@
spring.profiles.active=myprofile
my.property=frompropertiesfile
the.property=frompropertiesfile
one.more=${my.property}

View File

@ -1 +1,2 @@
my.property=frommorepropertiesfile
the.property=frommorepropertiesfile

View File

@ -1 +1,2 @@
foo=bar
bar=override

View File

@ -1 +1,2 @@
foo=spam
bar=some

View File

@ -1 +1,2 @@
my.property=fromspecificlocation
the.property=fromspecificlocation

View File

@ -1 +1,2 @@
my.property=frompropertiesfile
the.property=frompropertiesfile