diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java index 6a2b360fd12..29eda77b3a5 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java @@ -32,8 +32,10 @@ import java.util.stream.Collectors; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.beans.BeansException; import org.springframework.beans.CachedIntrospectionResults; import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader; import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory; @@ -56,6 +58,7 @@ import org.springframework.context.annotation.AnnotatedBeanDefinitionReader; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigUtils; import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; +import org.springframework.context.annotation.ConfigurationClassPostProcessor; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.GenericTypeResolver; @@ -397,6 +400,7 @@ public class SpringApplication { if (this.lazyInitialization) { context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); } + context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context)); if (!NativeDetector.inNativeImage()) { // Load the sources Set sources = getAllSources(); @@ -1374,4 +1378,28 @@ public class SpringApplication { return new LinkedHashSet<>(list); } + /** + * {@link BeanFactoryPostProcessor} to re-order our property sources below any + * {@code @PropertySource} items added by the {@link ConfigurationClassPostProcessor}. + */ + private static class PropertySourceOrderingBeanFactoryPostProcessor implements BeanFactoryPostProcessor, Ordered { + + private final ConfigurableApplicationContext context; + + PropertySourceOrderingBeanFactoryPostProcessor(ConfigurableApplicationContext context) { + this.context = context; + } + + @Override + public int getOrder() { + return Ordered.HIGHEST_PRECEDENCE; + } + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + DefaultPropertiesPropertySource.moveToEnd(this.context.getEnvironment()); + } + + } + } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java index 38e4608dbb8..732ba63cdf4 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java @@ -1250,6 +1250,16 @@ class SpringApplicationTests { assertThat(application.getEnvironmentPrefix()).isEqualTo("my"); } + @Test + void movesConfigClassPropertySourcesToEnd() { + SpringApplication application = new SpringApplication(PropertySourceConfig.class); + application.setWebApplicationType(WebApplicationType.NONE); + application.setDefaultProperties(Collections.singletonMap("test.name", "test")); + this.context = application.run(); + assertThat(this.context.getEnvironment().getProperty("test.name")) + .isEqualTo("spring-application-config-property-source"); + } + @Test void deregistersShutdownHookForFailedApplicationContext() { SpringApplication application = new SpringApplication(BrokenPostConstructConfig.class); @@ -1666,6 +1676,12 @@ class SpringApplicationTests { } + @Configuration(proxyBeanMethods = false) + @org.springframework.context.annotation.PropertySource("classpath:spring-application-config-property-source.properties") + static class PropertySourceConfig { + + } + static class ExitStatusException extends RuntimeException implements ExitCodeGenerator { @Override diff --git a/spring-boot-project/spring-boot/src/test/resources/spring-application-config-property-source.properties b/spring-boot-project/spring-boot/src/test/resources/spring-application-config-property-source.properties new file mode 100644 index 00000000000..c1b09576e25 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/resources/spring-application-config-property-source.properties @@ -0,0 +1 @@ +test.name=spring-application-config-property-source \ No newline at end of file