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
This commit is contained in:
Andy Wilkinson 2015-12-01 15:40:03 +00:00
parent 008f2a8874
commit 8618ec89b1
2 changed files with 43 additions and 3 deletions

View File

@ -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<EnvironmentPostProcessor> postProcessors = SpringFactoriesLoader
.loadFactories(EnvironmentPostProcessor.class,
getClass().getClassLoader());
List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
postProcessors.add(this);
AnnotationAwareOrderComparator.sort(postProcessors);
for (EnvironmentPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessEnvironment(event.getEnvironment(),
event.getSpringApplication());
}
}
List<EnvironmentPostProcessor> loadPostProcessors() {
return SpringFactoriesLoader.loadFactories(EnvironmentPostProcessor.class,
getClass().getClassLoader());
}
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment,
SpringApplication application) {

View File

@ -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<EnvironmentPostProcessor> loadPostProcessors() {
return new ArrayList<EnvironmentPostProcessor>(
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)));
}
}
}