From 8618ec89b1dbcb45c9c1fe86d7ef073ee2e60ce0 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 1 Dec 2015 15:40:03 +0000 Subject: [PATCH] Ensure that environment post processors are ordered correctly Previously, ConfigFileApplicationListener would always add itself to the end of the list of environment post processors loaded via spring.factories. This meant that its order (highest precedence + 10) would not be honoured and it would only be in the right place in the list if any other post processors happened to have a higher precedence. This commit updates ConfigFileApplicationListener to sort the list of post processors using AnnotationAwareOrderComparator once its added itself to the list. Closes gh-4595 --- .../config/ConfigFileApplicationListener.java | 11 ++++-- .../ConfigFileApplicationListenerTests.java | 35 +++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) 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 e8389745f6a..cf56bb4ce43 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 @@ -47,6 +47,7 @@ import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.ConfigurationClassPostProcessor; import org.springframework.core.Ordered; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.env.ConfigurableEnvironment; @@ -153,16 +154,20 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor, private void onApplicationEnvironmentPreparedEvent( ApplicationEnvironmentPreparedEvent event) { - List postProcessors = SpringFactoriesLoader - .loadFactories(EnvironmentPostProcessor.class, - getClass().getClassLoader()); + List postProcessors = loadPostProcessors(); postProcessors.add(this); + AnnotationAwareOrderComparator.sort(postProcessors); for (EnvironmentPostProcessor postProcessor : postProcessors) { postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication()); } } + List loadPostProcessors() { + return SpringFactoriesLoader.loadFactories(EnvironmentPostProcessor.class, + getClass().getClassLoader()); + } + @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { 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 d15c8d558c8..97a49e60051 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 @@ -44,8 +44,10 @@ import org.springframework.beans.CachedIntrospectionResults; import org.springframework.boot.Banner; import org.springframework.boot.SpringApplication; import org.springframework.boot.context.config.ConfigFileApplicationListener.ConfigurationPropertySources; +import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.boot.context.event.ApplicationPreparedEvent; import org.springframework.boot.env.EnumerableCompositePropertySource; +import org.springframework.boot.env.EnvironmentPostProcessor; import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.boot.test.OutputCapture; import org.springframework.context.ConfigurableApplicationContext; @@ -53,6 +55,8 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.context.annotation.PropertySource; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.MutablePropertySources; @@ -67,6 +71,7 @@ import org.springframework.util.StringUtils; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; @@ -445,6 +450,13 @@ public class ConfigFileApplicationListenerTests { validateProfilePrecedence(null, "other", "dev"); } + @Test + public void postProcessorsAreOrderedCorrectly() { + TestConfigFileApplicationListener testListener = new TestConfigFileApplicationListener(); + testListener.onApplicationEvent(new ApplicationEnvironmentPreparedEvent( + this.application, new String[0], this.environment)); + } + private void validateProfilePrecedence(String... profiles) { ApplicationPreparedEvent event = new ApplicationPreparedEvent( new SpringApplication(), new String[0], @@ -868,4 +880,27 @@ public class ConfigFileApplicationListenerTests { } + private static class TestConfigFileApplicationListener + extends ConfigFileApplicationListener { + + @Override + List loadPostProcessors() { + return new ArrayList( + Arrays.asList(new LowestPrecedenceEnvironmentPostProcessor())); + } + + } + + @Order(Ordered.LOWEST_PRECEDENCE) + private static class LowestPrecedenceEnvironmentPostProcessor + implements EnvironmentPostProcessor { + + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, + SpringApplication application) { + assertThat(environment.getPropertySources().size(), is(equalTo(4))); + } + + } + }