From 44c979beb0979a887c901a9b9d9742b0eb64da1c Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 17 May 2022 21:51:00 -0700 Subject: [PATCH] Reorder default property sources after @PropertySource processing Update `SpringApplication` so that the `DefaultPropertiesPropertySource` is moved to the end after `@PropertySource` annotations have been processed. This restores functionality that used to be handled by the `ConfigFileApplicationListener` and was inadvertently dropped when the `ConfigDataEnvironmentPostProcessor` was developed. Fixes gh-31068 --- .../boot/SpringApplication.java | 29 +++++++++++++++++++ .../boot/SpringApplicationTests.java | 16 ++++++++++ ...lication-config-property-source.properties | 1 + 3 files changed, 46 insertions(+) create mode 100644 spring-boot-project/spring-boot/src/test/resources/spring-application-config-property-source.properties 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 643d724915..f9c944ca85 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 @@ -33,8 +33,10 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeanUtils; +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.BeanDefinitionRegistry; @@ -56,9 +58,11 @@ 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; +import org.springframework.core.Ordered; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.env.CommandLinePropertySource; import org.springframework.core.env.CompositePropertySource; @@ -434,6 +438,7 @@ public class SpringApplication { if (this.lazyInitialization) { context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); } + context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context)); // Load the sources Set sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); @@ -1430,4 +1435,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 6f1cb74228..acf37d796a 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 @@ -1309,6 +1309,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); @@ -1667,6 +1677,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 0000000000..c1b09576e2 --- /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