From 919d0c617227bff1bfd58ed57d9d5080c82f6ac1 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 25 Nov 2016 10:05:16 +0000 Subject: [PATCH 1/2] Use data binding to access spring.profiles .active and .include Previously, spring.profiles.active and spring.profiles.include were looked up manually. This meant that configuration that used indexes (for example spring.profiles.active[0]=dev) were not bound. As a result, YAML lists did not work. This commit updates ConfigFileApplicationListener to use a RelaxedDataBinder to retrieve the values of spring.profiles.active and spring.profiles.include, thereby reusing the data binding logic that supports property names with indexes. See gh-6995 --- .../config/ConfigFileApplicationListener.java | 84 +++++++++++++++---- 1 file changed, 66 insertions(+), 18 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 f67ebf28849..85c6bb7b939 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 @@ -36,6 +36,8 @@ import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.bind.PropertiesConfigurationFactory; +import org.springframework.boot.bind.PropertySourcesPropertyValues; +import org.springframework.boot.bind.RelaxedDataBinder; import org.springframework.boot.bind.RelaxedPropertyResolver; import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.boot.context.event.ApplicationPreparedEvent; @@ -55,6 +57,7 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.EnumerablePropertySource; import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.PropertySource; +import org.springframework.core.env.PropertySources; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; @@ -390,8 +393,8 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor, } // Any pre-existing active profiles set via property sources (e.g. System // properties) take precedence over those added in config files. - Set activeProfiles = getProfilesForValue( - this.environment.getProperty(ACTIVE_PROFILES_PROPERTY)); + Set activeProfiles = bindSpringProfiles( + this.environment.getPropertySources()).getActiveProfiles(); maybeActivateProfiles(activeProfiles); return activeProfiles; } @@ -506,12 +509,23 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor, } private void handleProfileProperties(PropertySource propertySource) { - Set activeProfiles = getProfilesForValue( - propertySource.getProperty(ACTIVE_PROFILES_PROPERTY)); - maybeActivateProfiles(activeProfiles); - Set includeProfiles = getProfilesForValue( - propertySource.getProperty(INCLUDE_PROFILES_PROPERTY)); - addProfiles(includeProfiles); + SpringProfiles springProfiles = bindSpringProfiles(propertySource); + maybeActivateProfiles(springProfiles.getActiveProfiles()); + addProfiles(springProfiles.getIncludeProfiles()); + } + + private SpringProfiles bindSpringProfiles(PropertySource propertySource) { + MutablePropertySources propertySources = new MutablePropertySources(); + propertySources.addFirst(propertySource); + return bindSpringProfiles(propertySources); + } + + private SpringProfiles bindSpringProfiles(PropertySources propertySources) { + SpringProfiles springProfiles = new SpringProfiles(); + RelaxedDataBinder dataBinder = new RelaxedDataBinder(springProfiles, + "spring.profiles"); + dataBinder.bind(new PropertySourcesPropertyValues(propertySources)); + return springProfiles; } private void maybeActivateProfiles(Set profiles) { @@ -540,16 +554,6 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor, } } - private Set getProfilesForValue(Object property) { - String value = (property == null ? null : property.toString()); - Set profileNames = asResolvedSet(value, null); - Set profiles = new LinkedHashSet(); - for (String profileName : profileNames) { - profiles.add(new Profile(profileName)); - } - return profiles; - } - private void addProfiles(Set profiles) { for (Profile profile : profiles) { this.profiles.add(profile); @@ -750,4 +754,48 @@ public class ConfigFileApplicationListener implements EnvironmentPostProcessor, } + /** + * Holder for {@code spring.profiles} properties. + */ + static final class SpringProfiles { + + private List active = new ArrayList(); + + private List include = new ArrayList(); + + public List getActive() { + return this.active; + } + + public void setActive(List active) { + this.active = active; + } + + public List getInclude() { + return this.include; + } + + public void setInclude(List include) { + this.include = include; + } + + Set getActiveProfiles() { + return asProfileSet(this.active); + } + + Set getIncludeProfiles() { + return asProfileSet(this.include); + } + + private Set asProfileSet(List profileNames) { + List profiles = new ArrayList(); + for (String profileName : profileNames) { + profiles.add(new Profile(profileName)); + } + Collections.reverse(profiles); + return new LinkedHashSet(profiles); + } + + } + } From f64d5303cf761dcbf85d929e5888d5636732a391 Mon Sep 17 00:00:00 2001 From: Phillip Johnson Date: Tue, 18 Oct 2016 00:38:52 -0400 Subject: [PATCH 2/2] Document and test array support for spring.profiles.* Closes gh-7175 Closes gh-6995 --- .../main/asciidoc/appendix-application-properties.adoc | 4 ++-- .../src/main/asciidoc/spring-boot-features.adoc | 4 +++- .../config/ConfigFileApplicationListenerTests.java | 8 ++++++++ .../src/test/resources/testsetmultiprofileslist.yml | 6 ++++++ 4 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 spring-boot/src/test/resources/testsetmultiprofileslist.yml diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 8cfeefbbd72..3c41553d818 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -128,8 +128,8 @@ content into your application; rather pick only the properties that you need. spring.pid.file= # Location of the PID file to write (if ApplicationPidFileWriter is used). # PROFILES - spring.profiles.active= # Comma-separated list of <>. - spring.profiles.include= # Unconditionally activate the specified comma separated profiles. + spring.profiles.active= # Comma-separated list (or list if using YAML) of <>. + spring.profiles.include= # Unconditionally activate the specified comma separated profiles (or list of profiles if using YAML). # SENDGRID ({sc-spring-boot-autoconfigure}/sendgrid/SendGridAutoConfiguration.{sc-ext}[SendGridAutoConfiguration]) spring.sendgrid.api-key= # SendGrid api key (alternative to username/password) diff --git a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index c8b29eecd58..5c9de27990e 100644 --- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -1173,7 +1173,9 @@ For example, when an application with following properties is run using the swit my.property: fromyamlfile --- spring.profiles: prod - spring.profiles.include: proddb,prodmq + spring.profiles.include: + - proddb + - prodmq ---- NOTE: Remember that the `spring.profiles` property can be defined in a YAML document 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 5461a70b482..4221a73229e 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 @@ -536,6 +536,14 @@ public class ConfigFileApplicationListenerTests { "healthcheck"); } + @Test + public void yamlSetsMultiProfilesWhenListProvided() throws Exception { + this.initializer.setSearchNames("testsetmultiprofileslist"); + this.initializer.postProcessEnvironment(this.environment, this.application); + assertThat(this.environment.getActiveProfiles()).containsExactly("dev", + "healthcheck"); + } + @Test public void yamlSetsMultiProfilesWithWhitespace() throws Exception { this.initializer.setSearchNames("testsetmultiprofileswhitespace"); diff --git a/spring-boot/src/test/resources/testsetmultiprofileslist.yml b/spring-boot/src/test/resources/testsetmultiprofileslist.yml new file mode 100644 index 00000000000..02deecd5bae --- /dev/null +++ b/spring-boot/src/test/resources/testsetmultiprofileslist.yml @@ -0,0 +1,6 @@ +--- +spring: + profiles: + active: + - dev + - healthcheck \ No newline at end of file