Skip to content

Commit 6f26614

Browse files
nguyensachmbhave
authored andcommitted
Process additional profiles before config files processing
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 spring-projectsgh-25817
1 parent 269fc68 commit 6f26614

File tree

6 files changed

+100
-11
lines changed

6 files changed

+100
-11
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java

+1-11
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@
154154
* @author Madhura Bhave
155155
* @author Brian Clozel
156156
* @author Ethan Rubinson
157+
* @author Nguyen Bao Sach
157158
* @since 1.0.0
158159
* @see #run(Class, String[])
159160
* @see #run(Class[], String[])
@@ -373,7 +374,6 @@ private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners
373374
ConfigurationPropertySources.attach(environment);
374375
listeners.environmentPrepared(bootstrapContext, environment);
375376
DefaultPropertiesPropertySource.moveToEnd(environment);
376-
configureAdditionalProfiles(environment);
377377
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
378378
"Environment prefix cannot be set via properties.");
379379
bindToSpringApplication(environment);
@@ -558,16 +558,6 @@ protected void configurePropertySources(ConfigurableEnvironment environment, Str
558558
protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
559559
}
560560

561-
private void configureAdditionalProfiles(ConfigurableEnvironment environment) {
562-
if (!CollectionUtils.isEmpty(this.additionalProfiles)) {
563-
Set<String> profiles = new LinkedHashSet<>(Arrays.asList(environment.getActiveProfiles()));
564-
if (!profiles.containsAll(this.additionalProfiles)) {
565-
profiles.addAll(this.additionalProfiles);
566-
environment.setActiveProfiles(StringUtils.toStringArray(profiles));
567-
}
568-
}
569-
}
570-
571561
private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
572562
if (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
573563
Boolean ignore = environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE);

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessor.java

+15
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import java.util.Arrays;
2020
import java.util.Collection;
2121
import java.util.Collections;
22+
import java.util.LinkedHashSet;
23+
import java.util.Set;
2224
import java.util.function.Supplier;
2325

2426
import org.apache.commons.logging.Log;
@@ -34,13 +36,16 @@
3436
import org.springframework.core.io.DefaultResourceLoader;
3537
import org.springframework.core.io.ResourceLoader;
3638
import org.springframework.core.log.LogMessage;
39+
import org.springframework.util.CollectionUtils;
40+
import org.springframework.util.StringUtils;
3741

3842
/**
3943
* {@link EnvironmentPostProcessor} that loads and applies {@link ConfigData} to Spring's
4044
* {@link Environment}.
4145
*
4246
* @author Phillip Webb
4347
* @author Madhura Bhave
48+
* @author Nguyen Bao Sach
4449
* @since 2.4.0
4550
*/
4651
public class ConfigDataEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
@@ -99,6 +104,7 @@ void postProcessEnvironment(ConfigurableEnvironment environment, ResourceLoader
99104
catch (UseLegacyConfigProcessingException ex) {
100105
this.logger.debug(LogMessage.format("Switching to legacy config file processing [%s]",
101106
ex.getConfigurationProperty()));
107+
configureAdditionalProfiles(environment, additionalProfiles);
102108
postProcessUsingLegacyApplicationListener(environment, resourceLoader);
103109
}
104110
}
@@ -109,6 +115,15 @@ ConfigDataEnvironment getConfigDataEnvironment(ConfigurableEnvironment environme
109115
additionalProfiles, this.environmentUpdateListener);
110116
}
111117

118+
private void configureAdditionalProfiles(ConfigurableEnvironment environment,
119+
Collection<String> additionalProfiles) {
120+
if (!CollectionUtils.isEmpty(additionalProfiles)) {
121+
Set<String> profiles = new LinkedHashSet<>(additionalProfiles);
122+
profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
123+
environment.setActiveProfiles(StringUtils.toStringArray(profiles));
124+
}
125+
}
126+
112127
private void postProcessUsingLegacyApplicationListener(ConfigurableEnvironment environment,
113128
ResourceLoader resourceLoader) {
114129
getLegacyListener().addPropertySources(environment, resourceLoader);

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java

+12
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@
147147
* @author Brian Clozel
148148
* @author Artsiom Yudovin
149149
* @author Marten Deinum
150+
* @author Nguyen Bao Sach
150151
*/
151152
@ExtendWith(OutputCaptureExtension.class)
152153
class SpringApplicationTests {
@@ -604,6 +605,17 @@ void addProfilesOrder() {
604605
assertThat(environment.getActiveProfiles()).containsExactly("bar", "spam", "foo");
605606
}
606607

608+
@Test
609+
void includeProfilesOrder() {
610+
SpringApplication application = new SpringApplication(ExampleConfig.class);
611+
application.setWebApplicationType(WebApplicationType.NONE);
612+
ConfigurableEnvironment environment = new StandardEnvironment();
613+
application.setEnvironment(environment);
614+
this.context = application.run("--spring.profiles.active=bar,spam", "--spring.profiles.include=foo");
615+
// Since Boot 2.4 included profiles should always be last
616+
assertThat(environment.getActiveProfiles()).containsExactly("bar", "spam", "foo");
617+
}
618+
607619
@Test
608620
void addProfilesOrderWithProperties() {
609621
SpringApplication application = new SpringApplication(ExampleConfig.class);

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorTests.java

+19
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
*
4949
* @author Phillip Webb
5050
* @author Madhura Bhave
51+
* @author Nguyen Bao Sach
5152
*/
5253
@ExtendWith(MockitoExtension.class)
5354
class ConfigDataEnvironmentPostProcessorTests {
@@ -82,6 +83,7 @@ void postProcessEnvironmentWhenNoLoaderCreatesDefaultLoaderInstance() {
8283
verify(this.postProcessor).getConfigDataEnvironment(any(), this.resourceLoaderCaptor.capture(), any());
8384
verify(this.configDataEnvironment).processAndApply();
8485
assertThat(this.resourceLoaderCaptor.getValue()).isInstanceOf(DefaultResourceLoader.class);
86+
assertThat(this.environment.getActiveProfiles()).isEmpty();
8587
}
8688

8789
@Test
@@ -93,6 +95,7 @@ void postProcessEnvironmentWhenCustomLoaderUsesSpecifiedLoaderInstance() {
9395
verify(this.postProcessor).getConfigDataEnvironment(any(), this.resourceLoaderCaptor.capture(), any());
9496
verify(this.configDataEnvironment).processAndApply();
9597
assertThat(this.resourceLoaderCaptor.getValue()).isSameAs(resourceLoader);
98+
assertThat(this.environment.getActiveProfiles()).isEmpty();
9699
}
97100

98101
@Test
@@ -103,6 +106,7 @@ void postProcessEnvironmentWhenHasAdditionalProfilesOnSpringApplicationUsesAddit
103106
verify(this.postProcessor).getConfigDataEnvironment(any(), any(), this.additionalProfilesCaptor.capture());
104107
verify(this.configDataEnvironment).processAndApply();
105108
assertThat(this.additionalProfilesCaptor.getValue()).containsExactly("dev");
109+
assertThat(this.environment.getActiveProfiles()).isEmpty();
106110
}
107111

108112
@Test
@@ -115,6 +119,21 @@ void postProcessEnvironmentWhenUseLegacyProcessingSwitchesToLegacyMethod() {
115119
this.postProcessor.postProcessEnvironment(this.environment, this.application);
116120
verifyNoInteractions(this.configDataEnvironment);
117121
verify(legacyListener).addPropertySources(eq(this.environment), any(DefaultResourceLoader.class));
122+
assertThat(this.environment.getActiveProfiles()).isEmpty();
123+
}
124+
125+
@Test
126+
void postProcessEnvironmentWhenHasAdditionalProfilesViaProgrammaticallySettingAndUseLegacyProcessing() {
127+
this.application.setAdditionalProfiles("dev");
128+
ConfigDataEnvironmentPostProcessor.LegacyConfigFileApplicationListener legacyListener = mock(
129+
ConfigDataEnvironmentPostProcessor.LegacyConfigFileApplicationListener.class);
130+
willThrow(new UseLegacyConfigProcessingException(null)).given(this.postProcessor)
131+
.getConfigDataEnvironment(any(), any(), any());
132+
willReturn(legacyListener).given(this.postProcessor).getLegacyListener();
133+
this.postProcessor.postProcessEnvironment(this.environment, this.application);
134+
verifyNoInteractions(this.configDataEnvironment);
135+
verify(legacyListener).addPropertySources(eq(this.environment), any(DefaultResourceLoader.class));
136+
assertThat(this.environment.getActiveProfiles()).containsExactly("dev");
118137
}
119138

120139
@Test

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigFileApplicationListenerLegacyReproTests.java

+12
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
*
3434
* @author Phillip Webb
3535
* @author Dave Syer
36+
* @author Nguyen Bao Sach
3637
*/
3738
@ExtendWith(UseLegacyProcessing.class)
3839
class ConfigFileApplicationListenerLegacyReproTests {
@@ -167,6 +168,17 @@ void reverseOrderOfProfilesWithYamlAndNoOverride() {
167168
assertVersionProperty(this.context, "A", "C", "A");
168169
}
169170

171+
@Test
172+
void additionalProfilesViaProgrammaticallySetting() {
173+
// gh-25704
174+
SpringApplication application = new SpringApplication(Config.class);
175+
application.setWebApplicationType(WebApplicationType.NONE);
176+
application.setAdditionalProfiles("dev");
177+
this.context = application.run();
178+
assertThat(this.context.getEnvironment().acceptsProfiles(Profiles.of("dev"))).isTrue();
179+
assertThat(this.context.getEnvironment().getProperty("my.property")).isEqualTo("fromdevpropertiesfile");
180+
}
181+
170182
private void assertVersionProperty(ConfigurableApplicationContext context, String expectedVersion,
171183
String... expectedActiveProfiles) {
172184
assertThat(context.getEnvironment().getActiveProfiles()).isEqualTo(expectedActiveProfiles);

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigFileApplicationListenerTests.java

+41
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
* @author Eddú Meléndez
7171
* @author Madhura Bhave
7272
* @author Scott Frederick
73+
* @author Nguyen Bao Sach
7374
*/
7475
@Deprecated
7576
@ExtendWith({ OutputCaptureExtension.class, UseLegacyProcessing.class })
@@ -1150,6 +1151,46 @@ void locationsWithWildcardFilesShouldIgnoreHiddenDirectories() {
11501151
assertThat(this.environment.getProperty("fourth.property")).isNull();
11511152
}
11521153

1154+
@Test
1155+
void additionalProfilesCanBeIncludedFromProgrammaticallySetting() {
1156+
// gh-25704
1157+
SpringApplication application = new SpringApplication(Config.class);
1158+
application.setWebApplicationType(WebApplicationType.NONE);
1159+
application.setAdditionalProfiles("dev");
1160+
this.context = application.run();
1161+
// Active profile should win over default
1162+
assertThat(this.context.getEnvironment().getProperty("my.property")).isEqualTo("fromdevpropertiesfile");
1163+
}
1164+
1165+
@Test
1166+
void twoAdditionalProfilesCanBeIncludedFromProgrammaticallySetting() {
1167+
// gh-25704
1168+
SpringApplication application = new SpringApplication(Config.class);
1169+
application.setWebApplicationType(WebApplicationType.NONE);
1170+
application.setAdditionalProfiles("other", "dev");
1171+
this.context = application.run();
1172+
assertThat(this.context.getEnvironment().getProperty("my.property")).isEqualTo("fromdevpropertiesfile");
1173+
}
1174+
1175+
@Test
1176+
void includeProfilesOrder() {
1177+
SpringApplication application = new SpringApplication(Config.class);
1178+
application.setWebApplicationType(WebApplicationType.NONE);
1179+
this.context = application.run("--spring.profiles.active=bar,spam", "--spring.profiles.include=foo");
1180+
// Before Boot 2.4 included profiles should always be first
1181+
assertThat(this.context.getEnvironment().getActiveProfiles()).containsExactly("foo", "bar", "spam");
1182+
}
1183+
1184+
@Test
1185+
void addProfilesOrder() {
1186+
SpringApplication application = new SpringApplication(Config.class);
1187+
application.setWebApplicationType(WebApplicationType.NONE);
1188+
application.setAdditionalProfiles("foo");
1189+
this.context = application.run("--spring.profiles.active=bar,spam");
1190+
// Before Boot 2.4 additional profiles should always be first
1191+
assertThat(this.context.getEnvironment().getActiveProfiles()).containsExactly("foo", "bar", "spam");
1192+
}
1193+
11531194
private Condition<ConfigurableEnvironment> matchingPropertySource(final String sourceName) {
11541195
return new Condition<ConfigurableEnvironment>("environment containing property source " + sourceName) {
11551196

0 commit comments

Comments
 (0)