Resolve placeholders against the env in active/include profiles values

The changes made in 919d0c61 meant that the value of
spring.profiles.active or spring.profiles.include was only processed
when a single property source, the property source for the config file
being read, was available. This meant that any placeholders in those
values would only be resolved against properties in the configuration
file rather than against the entire environment.

This commit updates the binding process so that placeholder resolution
is not performed during binding against a single configuration file.
Once binding has completed, the bounds values are post-processed to
resolve and placeholders that they may contain.

The two-step process described above is used in preference to binding
against the whole environment. This avoids a problem with profiles
that are active or included by property sources in the environment
being processed repeatedly.

Closes gh-8234
This commit is contained in:
Andy Wilkinson 2017-02-08 14:24:22 +00:00
parent da8362a2da
commit 7d247a71e4
4 changed files with 43 additions and 3 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2016 the original author or authors.
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -63,8 +63,21 @@ public class PropertySourcesPropertyValues implements PropertyValues {
* @param propertySources a PropertySources instance
*/
public PropertySourcesPropertyValues(PropertySources propertySources) {
this(propertySources, true);
}
/**
* Create a new PropertyValues from the given PropertySources that will optionally
* resolve placeholders.
* @param propertySources a PropertySources instance
* @param resolvePlaceholders {@code true} if placeholders should be resolved,
* otherwise {@code false}
* @since 1.5.2
*/
public PropertySourcesPropertyValues(PropertySources propertySources,
boolean resolvePlaceholders) {
this(propertySources, (Collection<String>) null, PropertyNamePatternsMatcher.ALL,
true);
resolvePlaceholders);
}
/**

View File

@ -527,10 +527,20 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
SpringProfiles springProfiles = new SpringProfiles();
RelaxedDataBinder dataBinder = new RelaxedDataBinder(springProfiles,
"spring.profiles");
dataBinder.bind(new PropertySourcesPropertyValues(propertySources));
dataBinder.bind(new PropertySourcesPropertyValues(propertySources, false));
springProfiles.setActive(resolvePlaceholders(springProfiles.getActive()));
springProfiles.setInclude(resolvePlaceholders(springProfiles.getInclude()));
return springProfiles;
}
private List<String> resolvePlaceholders(List<String> values) {
List<String> resolved = new ArrayList<String>();
for (String value : values) {
resolved.add(this.environment.resolvePlaceholders(value));
}
return resolved;
}
private void maybeActivateProfiles(Set<Profile> profiles) {
if (this.activatedProfiles) {
if (!profiles.isEmpty()) {

View File

@ -24,7 +24,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import ch.qos.logback.classic.BasicConfigurator;
@ -849,6 +851,20 @@ public class ConfigFileApplicationListenerTests {
.isFalse();
}
@Test
public void activeProfilesCanBeConfiguredUsingPlaceholdersResolvedAgainstTheEnvironment()
throws Exception {
Map<String, Object> source = new HashMap<String, Object>();
source.put("activeProfile", "testPropertySource");
org.springframework.core.env.PropertySource<?> propertySource = new MapPropertySource(
"test", source);
this.environment.getPropertySources().addLast(propertySource);
this.initializer.setSearchNames("testactiveprofiles");
this.initializer.postProcessEnvironment(this.environment, this.application);
assertThat(this.environment.getActiveProfiles())
.containsExactly("testPropertySource");
}
private Condition<ConfigurableEnvironment> matchingPropertySource(
final String sourceName) {
return new Condition<ConfigurableEnvironment>(

View File

@ -0,0 +1 @@
spring.profiles.active=${activeProfile:propertiesfile}