diff --git a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 18aded06ea..41eba5e548 100644 --- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -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 diff --git a/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java b/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java index 3aaad79a91..3682df539a 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java @@ -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); } } diff --git a/spring-boot/src/test/java/org/springframework/boot/bind/PropertySourcesBindingTests.java b/spring-boot/src/test/java/org/springframework/boot/bind/PropertySourcesBindingTests.java index ecbf62e596..eaaf1e535b 100644 --- a/spring-boot/src/test/java/org/springframework/boot/bind/PropertySourcesBindingTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/bind/PropertySourcesBindingTests.java @@ -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; } diff --git a/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigFileApplicationListenerTests.java b/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigFileApplicationListenerTests.java index 38d2043a2e..f8eed47490 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigFileApplicationListenerTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigFileApplicationListenerTests.java @@ -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(); diff --git a/spring-boot/src/test/resources/enableprofile-myprofile.properties b/spring-boot/src/test/resources/enableprofile-myprofile.properties index 92ded544e1..caeddf9d47 100644 --- a/spring-boot/src/test/resources/enableprofile-myprofile.properties +++ b/spring-boot/src/test/resources/enableprofile-myprofile.properties @@ -1 +1,2 @@ my.property=fromprofilepropertiesfile +the.property=fromprofilepropertiesfile \ No newline at end of file diff --git a/spring-boot/src/test/resources/enableprofile.properties b/spring-boot/src/test/resources/enableprofile.properties index 1e4e426e17..8852852262 100644 --- a/spring-boot/src/test/resources/enableprofile.properties +++ b/spring-boot/src/test/resources/enableprofile.properties @@ -1,3 +1,4 @@ spring.profiles.active=myprofile my.property=frompropertiesfile +the.property=frompropertiesfile one.more=${my.property} diff --git a/spring-boot/src/test/resources/moreproperties.properties b/spring-boot/src/test/resources/moreproperties.properties index f55627b17f..90fbde1795 100644 --- a/spring-boot/src/test/resources/moreproperties.properties +++ b/spring-boot/src/test/resources/moreproperties.properties @@ -1 +1,2 @@ my.property=frommorepropertiesfile +the.property=frommorepropertiesfile \ No newline at end of file diff --git a/spring-boot/src/test/resources/override.properties b/spring-boot/src/test/resources/override.properties index 74d0a43fcc..37621c0a2c 100644 --- a/spring-boot/src/test/resources/override.properties +++ b/spring-boot/src/test/resources/override.properties @@ -1 +1,2 @@ foo=bar +bar=override diff --git a/spring-boot/src/test/resources/some.properties b/spring-boot/src/test/resources/some.properties index 376216c57e..8648daf6df 100644 --- a/spring-boot/src/test/resources/some.properties +++ b/spring-boot/src/test/resources/some.properties @@ -1 +1,2 @@ foo=spam +bar=some \ No newline at end of file diff --git a/spring-boot/src/test/resources/specificlocation.properties b/spring-boot/src/test/resources/specificlocation.properties index aaa8369be8..f037df5ff5 100644 --- a/spring-boot/src/test/resources/specificlocation.properties +++ b/spring-boot/src/test/resources/specificlocation.properties @@ -1 +1,2 @@ my.property=fromspecificlocation +the.property=fromspecificlocation \ No newline at end of file diff --git a/spring-boot/src/test/resources/testproperties.properties b/spring-boot/src/test/resources/testproperties.properties index dc7fdc02b7..c523d59058 100644 --- a/spring-boot/src/test/resources/testproperties.properties +++ b/spring-boot/src/test/resources/testproperties.properties @@ -1 +1,2 @@ my.property=frompropertiesfile +the.property=frompropertiesfile