Skip to content

Commit

Permalink
Process additional profiles before config files processing
Browse files Browse the repository at this point in the history
Additional profiles were being processed after config file processing
when legacy processing was used.
This commit also restores the order in which additional profiles are added
when legacy processing is used.
Active profiles take precedence over additional profiles.

See gh-25817
  • Loading branch information
nguyensach authored and mbhave committed May 11, 2021
1 parent 269fc68 commit 6f26614
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@
* @author Madhura Bhave
* @author Brian Clozel
* @author Ethan Rubinson
* @author Nguyen Bao Sach
* @since 1.0.0
* @see #run(Class, String[])
* @see #run(Class[], String[])
Expand Down Expand Up @@ -373,7 +374,6 @@ private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners
ConfigurationPropertySources.attach(environment);
listeners.environmentPrepared(bootstrapContext, environment);
DefaultPropertiesPropertySource.moveToEnd(environment);
configureAdditionalProfiles(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
"Environment prefix cannot be set via properties.");
bindToSpringApplication(environment);
Expand Down Expand Up @@ -558,16 +558,6 @@ protected void configurePropertySources(ConfigurableEnvironment environment, Str
protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
}

private void configureAdditionalProfiles(ConfigurableEnvironment environment) {
if (!CollectionUtils.isEmpty(this.additionalProfiles)) {
Set<String> profiles = new LinkedHashSet<>(Arrays.asList(environment.getActiveProfiles()));
if (!profiles.containsAll(this.additionalProfiles)) {
profiles.addAll(this.additionalProfiles);
environment.setActiveProfiles(StringUtils.toStringArray(profiles));
}
}
}

private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
if (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
Boolean ignore = environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.function.Supplier;

import org.apache.commons.logging.Log;
Expand All @@ -34,13 +36,16 @@
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.log.LogMessage;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

/**
* {@link EnvironmentPostProcessor} that loads and applies {@link ConfigData} to Spring's
* {@link Environment}.
*
* @author Phillip Webb
* @author Madhura Bhave
* @author Nguyen Bao Sach
* @since 2.4.0
*/
public class ConfigDataEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
Expand Down Expand Up @@ -99,6 +104,7 @@ void postProcessEnvironment(ConfigurableEnvironment environment, ResourceLoader
catch (UseLegacyConfigProcessingException ex) {
this.logger.debug(LogMessage.format("Switching to legacy config file processing [%s]",
ex.getConfigurationProperty()));
configureAdditionalProfiles(environment, additionalProfiles);
postProcessUsingLegacyApplicationListener(environment, resourceLoader);
}
}
Expand All @@ -109,6 +115,15 @@ ConfigDataEnvironment getConfigDataEnvironment(ConfigurableEnvironment environme
additionalProfiles, this.environmentUpdateListener);
}

private void configureAdditionalProfiles(ConfigurableEnvironment environment,
Collection<String> additionalProfiles) {
if (!CollectionUtils.isEmpty(additionalProfiles)) {
Set<String> profiles = new LinkedHashSet<>(additionalProfiles);
profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
environment.setActiveProfiles(StringUtils.toStringArray(profiles));
}
}

private void postProcessUsingLegacyApplicationListener(ConfigurableEnvironment environment,
ResourceLoader resourceLoader) {
getLegacyListener().addPropertySources(environment, resourceLoader);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@
* @author Brian Clozel
* @author Artsiom Yudovin
* @author Marten Deinum
* @author Nguyen Bao Sach
*/
@ExtendWith(OutputCaptureExtension.class)
class SpringApplicationTests {
Expand Down Expand Up @@ -604,6 +605,17 @@ void addProfilesOrder() {
assertThat(environment.getActiveProfiles()).containsExactly("bar", "spam", "foo");
}

@Test
void includeProfilesOrder() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
ConfigurableEnvironment environment = new StandardEnvironment();
application.setEnvironment(environment);
this.context = application.run("--spring.profiles.active=bar,spam", "--spring.profiles.include=foo");
// Since Boot 2.4 included profiles should always be last
assertThat(environment.getActiveProfiles()).containsExactly("bar", "spam", "foo");
}

@Test
void addProfilesOrderWithProperties() {
SpringApplication application = new SpringApplication(ExampleConfig.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
*
* @author Phillip Webb
* @author Madhura Bhave
* @author Nguyen Bao Sach
*/
@ExtendWith(MockitoExtension.class)
class ConfigDataEnvironmentPostProcessorTests {
Expand Down Expand Up @@ -82,6 +83,7 @@ void postProcessEnvironmentWhenNoLoaderCreatesDefaultLoaderInstance() {
verify(this.postProcessor).getConfigDataEnvironment(any(), this.resourceLoaderCaptor.capture(), any());
verify(this.configDataEnvironment).processAndApply();
assertThat(this.resourceLoaderCaptor.getValue()).isInstanceOf(DefaultResourceLoader.class);
assertThat(this.environment.getActiveProfiles()).isEmpty();
}

@Test
Expand All @@ -93,6 +95,7 @@ void postProcessEnvironmentWhenCustomLoaderUsesSpecifiedLoaderInstance() {
verify(this.postProcessor).getConfigDataEnvironment(any(), this.resourceLoaderCaptor.capture(), any());
verify(this.configDataEnvironment).processAndApply();
assertThat(this.resourceLoaderCaptor.getValue()).isSameAs(resourceLoader);
assertThat(this.environment.getActiveProfiles()).isEmpty();
}

@Test
Expand All @@ -103,6 +106,7 @@ void postProcessEnvironmentWhenHasAdditionalProfilesOnSpringApplicationUsesAddit
verify(this.postProcessor).getConfigDataEnvironment(any(), any(), this.additionalProfilesCaptor.capture());
verify(this.configDataEnvironment).processAndApply();
assertThat(this.additionalProfilesCaptor.getValue()).containsExactly("dev");
assertThat(this.environment.getActiveProfiles()).isEmpty();
}

@Test
Expand All @@ -115,6 +119,21 @@ void postProcessEnvironmentWhenUseLegacyProcessingSwitchesToLegacyMethod() {
this.postProcessor.postProcessEnvironment(this.environment, this.application);
verifyNoInteractions(this.configDataEnvironment);
verify(legacyListener).addPropertySources(eq(this.environment), any(DefaultResourceLoader.class));
assertThat(this.environment.getActiveProfiles()).isEmpty();
}

@Test
void postProcessEnvironmentWhenHasAdditionalProfilesViaProgrammaticallySettingAndUseLegacyProcessing() {
this.application.setAdditionalProfiles("dev");
ConfigDataEnvironmentPostProcessor.LegacyConfigFileApplicationListener legacyListener = mock(
ConfigDataEnvironmentPostProcessor.LegacyConfigFileApplicationListener.class);
willThrow(new UseLegacyConfigProcessingException(null)).given(this.postProcessor)
.getConfigDataEnvironment(any(), any(), any());
willReturn(legacyListener).given(this.postProcessor).getLegacyListener();
this.postProcessor.postProcessEnvironment(this.environment, this.application);
verifyNoInteractions(this.configDataEnvironment);
verify(legacyListener).addPropertySources(eq(this.environment), any(DefaultResourceLoader.class));
assertThat(this.environment.getActiveProfiles()).containsExactly("dev");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
*
* @author Phillip Webb
* @author Dave Syer
* @author Nguyen Bao Sach
*/
@ExtendWith(UseLegacyProcessing.class)
class ConfigFileApplicationListenerLegacyReproTests {
Expand Down Expand Up @@ -167,6 +168,17 @@ void reverseOrderOfProfilesWithYamlAndNoOverride() {
assertVersionProperty(this.context, "A", "C", "A");
}

@Test
void additionalProfilesViaProgrammaticallySetting() {
// gh-25704
SpringApplication application = new SpringApplication(Config.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.setAdditionalProfiles("dev");
this.context = application.run();
assertThat(this.context.getEnvironment().acceptsProfiles(Profiles.of("dev"))).isTrue();
assertThat(this.context.getEnvironment().getProperty("my.property")).isEqualTo("fromdevpropertiesfile");
}

private void assertVersionProperty(ConfigurableApplicationContext context, String expectedVersion,
String... expectedActiveProfiles) {
assertThat(context.getEnvironment().getActiveProfiles()).isEqualTo(expectedActiveProfiles);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
* @author Eddú Meléndez
* @author Madhura Bhave
* @author Scott Frederick
* @author Nguyen Bao Sach
*/
@Deprecated
@ExtendWith({ OutputCaptureExtension.class, UseLegacyProcessing.class })
Expand Down Expand Up @@ -1150,6 +1151,46 @@ void locationsWithWildcardFilesShouldIgnoreHiddenDirectories() {
assertThat(this.environment.getProperty("fourth.property")).isNull();
}

@Test
void additionalProfilesCanBeIncludedFromProgrammaticallySetting() {
// gh-25704
SpringApplication application = new SpringApplication(Config.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.setAdditionalProfiles("dev");
this.context = application.run();
// Active profile should win over default
assertThat(this.context.getEnvironment().getProperty("my.property")).isEqualTo("fromdevpropertiesfile");
}

@Test
void twoAdditionalProfilesCanBeIncludedFromProgrammaticallySetting() {
// gh-25704
SpringApplication application = new SpringApplication(Config.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.setAdditionalProfiles("other", "dev");
this.context = application.run();
assertThat(this.context.getEnvironment().getProperty("my.property")).isEqualTo("fromdevpropertiesfile");
}

@Test
void includeProfilesOrder() {
SpringApplication application = new SpringApplication(Config.class);
application.setWebApplicationType(WebApplicationType.NONE);
this.context = application.run("--spring.profiles.active=bar,spam", "--spring.profiles.include=foo");
// Before Boot 2.4 included profiles should always be first
assertThat(this.context.getEnvironment().getActiveProfiles()).containsExactly("foo", "bar", "spam");
}

@Test
void addProfilesOrder() {
SpringApplication application = new SpringApplication(Config.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.setAdditionalProfiles("foo");
this.context = application.run("--spring.profiles.active=bar,spam");
// Before Boot 2.4 additional profiles should always be first
assertThat(this.context.getEnvironment().getActiveProfiles()).containsExactly("foo", "bar", "spam");
}

private Condition<ConfigurableEnvironment> matchingPropertySource(final String sourceName) {
return new Condition<ConfigurableEnvironment>("environment containing property source " + sourceName) {

Expand Down

0 comments on commit 6f26614

Please sign in to comment.