Skip to content

Commit b75578d

Browse files
author
Dave Syer
committed
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
1 parent e81e949 commit b75578d

File tree

11 files changed

+62
-32
lines changed

11 files changed

+62
-32
lines changed

spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,11 +207,11 @@ sensible overriding of values, properties are considered in the the following or
207207
. OS environment variables.
208208
. JNDI attributes from `java:comp/env`
209209
. A `RandomValuePropertySource` that only has properties in `random.*`.
210-
. `@PropertySource` annotations on your `@Configuration` classes.
211210
. Application properties outside of your packaged jar (`application.properties`
212211
including YAML and profile variants).
213212
. Application properties packaged inside your jar (`application.properties`
214213
including YAML and profile variants).
214+
. `@PropertySource` annotations on your `@Configuration` classes.
215215
. Default properties (specified using `SpringApplication.setDefaultProperties`).
216216

217217
To provide a concrete example, suppose you develop a `@Component` that uses a

spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -497,19 +497,22 @@ public Object getProperty(String name) {
497497

498498
public static void finishAndRelocate(MutablePropertySources propertySources) {
499499
ConfigurationPropertySources removed = (ConfigurationPropertySources) propertySources
500-
.remove(ConfigurationPropertySources.NAME);
500+
.get(ConfigurationPropertySources.NAME);
501+
String name = ConfigurationPropertySources.NAME;
501502
if (removed != null) {
502503
for (PropertySource<?> propertySource : removed.sources) {
503504
if (propertySource instanceof EnumerableCompositePropertySource) {
504505
EnumerableCompositePropertySource composite = (EnumerableCompositePropertySource) propertySource;
505506
for (PropertySource<?> nested : composite.getSource()) {
506-
propertySources.addLast(nested);
507+
propertySources.addAfter(name, nested);
508+
name = nested.getName();
507509
}
508510
}
509511
else {
510-
propertySources.addLast(propertySource);
512+
propertySources.addAfter(name, propertySource);
511513
}
512514
}
515+
propertySources.remove(ConfigurationPropertySources.NAME);
513516
}
514517
}
515518

spring-boot/src/test/java/org/springframework/boot/bind/PropertySourcesBindingTests.java

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,23 @@ public class PropertySourcesBindingTests {
5353
private Wrapper properties;
5454

5555
@Test
56-
public void overridingOfPropertiesWorksAsExpected() {
56+
public void overridingOfPropertiesOrderOfAtPropertySources() {
57+
assertThat(this.properties.getBar(), is("override"));
58+
}
59+
60+
@Test
61+
public void overridingOfPropertiesAndBindToAtValue() {
5762
assertThat(this.foo, is(this.properties.getFoo()));
5863
}
5964

65+
@Test
66+
public void overridingOfPropertiesOrderOfApplicationProperties() {
67+
assertThat(this.properties.getFoo(), is("bucket"));
68+
}
69+
6070
@Import({ SomeConfig.class })
61-
@PropertySources({ @PropertySource("classpath:/override.properties"),
62-
@PropertySource("classpath:/some.properties") })
71+
@PropertySources({ @PropertySource("classpath:/some.properties"),
72+
@PropertySource("classpath:/override.properties") })
6373
@Configuration
6474
@EnableConfigurationProperties(Wrapper.class)
6575
public static class TestConfig {
@@ -81,6 +91,16 @@ public static class SomeConfig {
8191
public static class Wrapper {
8292
private String foo;
8393

94+
private String bar;
95+
96+
public String getBar() {
97+
return this.bar;
98+
}
99+
100+
public void setBar(String bar) {
101+
this.bar = bar;
102+
}
103+
84104
public String getFoo() {
85105
return this.foo;
86106
}

spring-boot/src/test/java/org/springframework/boot/context/config/ConfigFileApplicationListenerTests.java

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public class ConfigFileApplicationListenerTests {
8282

8383
@After
8484
public void cleanup() {
85-
System.clearProperty("my.property");
85+
System.clearProperty("the.property");
8686
System.clearProperty("spring.config.location");
8787
System.clearProperty("spring.main.showBanner");
8888
}
@@ -93,7 +93,7 @@ public void loadCustomResource() throws Exception {
9393
@Override
9494
public Resource getResource(final String location) {
9595
if (location.equals("classpath:/custom.properties")) {
96-
return new ByteArrayResource("my.property: fromcustom".getBytes(),
96+
return new ByteArrayResource("the.property: fromcustom".getBytes(),
9797
location) {
9898
@Override
9999
public String getFilename() {
@@ -111,15 +111,15 @@ public ClassLoader getClassLoader() {
111111
});
112112
this.initializer.setSearchNames("custom");
113113
this.initializer.onApplicationEvent(this.event);
114-
String property = this.environment.getProperty("my.property");
114+
String property = this.environment.getProperty("the.property");
115115
assertThat(property, equalTo("fromcustom"));
116116
}
117117

118118
@Test
119119
public void loadPropertiesFile() throws Exception {
120120
this.initializer.setSearchNames("testproperties");
121121
this.initializer.onApplicationEvent(this.event);
122-
String property = this.environment.getProperty("my.property");
122+
String property = this.environment.getProperty("the.property");
123123
assertThat(property, equalTo("frompropertiesfile"));
124124
}
125125

@@ -128,7 +128,7 @@ public void loadTwoPropertiesFile() throws Exception {
128128
EnvironmentTestUtils.addEnvironment(this.environment, "spring.config.location:"
129129
+ "classpath:application.properties,classpath:testproperties.properties");
130130
this.initializer.onApplicationEvent(this.event);
131-
String property = this.environment.getProperty("my.property");
131+
String property = this.environment.getProperty("the.property");
132132
assertThat(property, equalTo("frompropertiesfile"));
133133
}
134134

@@ -152,7 +152,7 @@ public void loadTwoPropertiesFilesWithProfilesAndSwitchOneOff() throws Exception
152152
assertEquals("myprofile",
153153
StringUtils.arrayToCommaDelimitedString(this.environment
154154
.getActiveProfiles()));
155-
String property = this.environment.getProperty("my.property");
155+
String property = this.environment.getProperty("the.property");
156156
// The value from the second file wins (no profile specific configuration is
157157
// actually loaded)
158158
assertThat(property, equalTo("frompropertiesfile"));
@@ -168,7 +168,7 @@ public void loadTwoPropertiesFilesWithProfilesAndSwitchOneOffFromSpecificLocatio
168168
assertEquals("myprofile",
169169
StringUtils.arrayToCommaDelimitedString(this.environment
170170
.getActiveProfiles()));
171-
String property = this.environment.getProperty("my.property");
171+
String property = this.environment.getProperty("the.property");
172172
// The value from the second file wins (no profile specific configuration is
173173
// actually loaded)
174174
assertThat(property, equalTo("frompropertiesfile"));
@@ -180,7 +180,7 @@ public void localFileTakesPrecedenceOverClasspath() throws Exception {
180180
assertThat(localFile.exists(), equalTo(false));
181181
try {
182182
Properties properties = new Properties();
183-
properties.put("my.property", "fromlocalfile");
183+
properties.put("the.property", "fromlocalfile");
184184
OutputStream out = new FileOutputStream(localFile);
185185
try {
186186
properties.store(out, "");
@@ -189,7 +189,7 @@ public void localFileTakesPrecedenceOverClasspath() throws Exception {
189189
out.close();
190190
}
191191
this.initializer.onApplicationEvent(this.event);
192-
String property = this.environment.getProperty("my.property");
192+
String property = this.environment.getProperty("the.property");
193193
assertThat(property, equalTo("fromlocalfile"));
194194
}
195195
finally {
@@ -213,7 +213,7 @@ public void loadTwoOfThreePropertiesFile() throws Exception {
213213
+ "classpath:testproperties.properties,"
214214
+ "classpath:nonexistent.properties");
215215
this.initializer.onApplicationEvent(this.event);
216-
String property = this.environment.getProperty("my.property");
216+
String property = this.environment.getProperty("the.property");
217217
assertThat(property, equalTo("frompropertiesfile"));
218218
}
219219

@@ -228,7 +228,7 @@ public void randomValue() throws Exception {
228228
public void loadTwoPropertiesFiles() throws Exception {
229229
this.initializer.setSearchNames("moreproperties,testproperties");
230230
this.initializer.onApplicationEvent(this.event);
231-
String property = this.environment.getProperty("my.property");
231+
String property = this.environment.getProperty("the.property");
232232
// The search order has highest precedence last (like merging a map)
233233
assertThat(property, equalTo("frompropertiesfile"));
234234
}
@@ -246,19 +246,19 @@ public void loadYamlFile() throws Exception {
246246
@Test
247247
public void commandLineWins() throws Exception {
248248
this.environment.getPropertySources().addFirst(
249-
new SimpleCommandLinePropertySource("--my.property=fromcommandline"));
249+
new SimpleCommandLinePropertySource("--the.property=fromcommandline"));
250250
this.initializer.setSearchNames("testproperties");
251251
this.initializer.onApplicationEvent(this.event);
252-
String property = this.environment.getProperty("my.property");
252+
String property = this.environment.getProperty("the.property");
253253
assertThat(property, equalTo("fromcommandline"));
254254
}
255255

256256
@Test
257257
public void systemPropertyWins() throws Exception {
258-
System.setProperty("my.property", "fromsystem");
258+
System.setProperty("the.property", "fromsystem");
259259
this.initializer.setSearchNames("testproperties");
260260
this.initializer.onApplicationEvent(this.event);
261-
String property = this.environment.getProperty("my.property");
261+
String property = this.environment.getProperty("the.property");
262262
assertThat(property, equalTo("fromsystem"));
263263
}
264264

@@ -285,7 +285,7 @@ public void defaultPropertyAsFallbackDuringFileParsing() throws Exception {
285285
.singletonMap("spring.config.name",
286286
(Object) "testproperties")));
287287
this.initializer.onApplicationEvent(this.event);
288-
String property = this.environment.getProperty("my.property");
288+
String property = this.environment.getProperty("the.property");
289289
assertThat(property, equalTo("frompropertiesfile"));
290290
}
291291

@@ -318,7 +318,7 @@ public void twoProfilesFromProperties() throws Exception {
318318
public void loadPropertiesThenProfilePropertiesActivatedInFirst() throws Exception {
319319
this.initializer.setSearchNames("enableprofile");
320320
this.initializer.onApplicationEvent(this.event);
321-
String property = this.environment.getProperty("my.property");
321+
String property = this.environment.getProperty("the.property");
322322
// The "myprofile" profile is activated in enableprofile.properties so its value
323323
// should show up here
324324
assertThat(property, equalTo("fromprofilepropertiesfile"));
@@ -334,7 +334,7 @@ public void loadPropertiesThenProfilePropertiesWithOverride() throws Exception {
334334
String property = this.environment.getProperty("other.property");
335335
// The "other" profile is activated before any processing starts
336336
assertThat(property, equalTo("fromotherpropertiesfile"));
337-
property = this.environment.getProperty("my.property");
337+
property = this.environment.getProperty("the.property");
338338
// The "myprofile" profile is activated in enableprofile.properties and "other"
339339
// was not activated by setting spring.profiles.active so "myprofile" should still
340340
// be activated
@@ -428,7 +428,7 @@ public void specificResource() throws Exception {
428428
EnvironmentTestUtils.addEnvironment(this.environment, "spring.config.location:"
429429
+ location);
430430
this.initializer.onApplicationEvent(this.event);
431-
String property = this.environment.getProperty("my.property");
431+
String property = this.environment.getProperty("the.property");
432432
assertThat(property, equalTo("fromspecificlocation"));
433433
assertThat(this.environment, containsPropertySource("applicationConfig: "
434434
+ "[classpath:specificlocation.properties]"));
@@ -463,7 +463,7 @@ public void propertySourceAnnotation() throws Exception {
463463
SpringApplication application = new SpringApplication(WithPropertySource.class);
464464
application.setWebEnvironment(false);
465465
ConfigurableApplicationContext context = application.run();
466-
String property = context.getEnvironment().getProperty("my.property");
466+
String property = context.getEnvironment().getProperty("the.property");
467467
assertThat(property, equalTo("fromspecificlocation"));
468468
assertThat(context.getEnvironment(),
469469
containsPropertySource("class path resource "
@@ -480,7 +480,7 @@ public void propertySourceAnnotationWithPlaceholder() throws Exception {
480480
application.setEnvironment(this.environment);
481481
application.setWebEnvironment(false);
482482
ConfigurableApplicationContext context = application.run();
483-
String property = context.getEnvironment().getProperty("my.property");
483+
String property = context.getEnvironment().getProperty("the.property");
484484
assertThat(property, equalTo("fromspecificlocation"));
485485
assertThat(context.getEnvironment(),
486486
containsPropertySource("class path resource "
@@ -494,7 +494,7 @@ public void propertySourceAnnotationWithName() throws Exception {
494494
WithPropertySourceAndName.class);
495495
application.setWebEnvironment(false);
496496
ConfigurableApplicationContext context = application.run();
497-
String property = context.getEnvironment().getProperty("my.property");
497+
String property = context.getEnvironment().getProperty("the.property");
498498
assertThat(property, equalTo("fromspecificlocation"));
499499
assertThat(context.getEnvironment(), containsPropertySource("foo"));
500500
context.close();
@@ -507,7 +507,7 @@ public void propertySourceAnnotationInProfile() throws Exception {
507507
application.setWebEnvironment(false);
508508
ConfigurableApplicationContext context = application
509509
.run("--spring.profiles.active=myprofile");
510-
String property = context.getEnvironment().getProperty("my.property");
510+
String property = context.getEnvironment().getProperty("the.property");
511511
assertThat(property, equalTo("frompropertiesfile"));
512512
assertThat(context.getEnvironment(),
513513
containsPropertySource("class path resource "
@@ -536,7 +536,7 @@ public void propertySourceAnnotationMultipleLocations() throws Exception {
536536
WithPropertySourceMultipleLocations.class);
537537
application.setWebEnvironment(false);
538538
ConfigurableApplicationContext context = application.run();
539-
String property = context.getEnvironment().getProperty("my.property");
539+
String property = context.getEnvironment().getProperty("the.property");
540540
assertThat(property, equalTo("frommorepropertiesfile"));
541541
assertThat(context.getEnvironment(),
542542
containsPropertySource("class path resource "
@@ -550,7 +550,7 @@ public void propertySourceAnnotationMultipleLocationsAndName() throws Exception
550550
WithPropertySourceMultipleLocationsAndName.class);
551551
application.setWebEnvironment(false);
552552
ConfigurableApplicationContext context = application.run();
553-
String property = context.getEnvironment().getProperty("my.property");
553+
String property = context.getEnvironment().getProperty("the.property");
554554
assertThat(property, equalTo("frommorepropertiesfile"));
555555
assertThat(context.getEnvironment(), containsPropertySource("foo"));
556556
context.close();
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
my.property=fromprofilepropertiesfile
2+
the.property=fromprofilepropertiesfile
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
spring.profiles.active=myprofile
22
my.property=frompropertiesfile
3+
the.property=frompropertiesfile
34
one.more=${my.property}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
my.property=frommorepropertiesfile
2+
the.property=frommorepropertiesfile
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
foo=bar
2+
bar=override
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
foo=spam
2+
bar=some
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
my.property=fromspecificlocation
2+
the.property=fromspecificlocation

0 commit comments

Comments
 (0)