Skip to content

Commit cab9bff

Browse files
committed
Log included profiles according to the processing order
This commit includes some refactoring of active profiles processing. Previously, there was a LIFO Queue for adding active profiles. Profiles that were added last, were processed first. Because of this reverse ordering, profiles were prepended to the environment to preserve the order in which they were logged. This however didn't work for "included" profiles as they were prepended to the environment even though they were processed after the active profile. In this commit, profiles are processed in a FIFO manner and processed as they're found. Fixes spring-projectsgh-11380
1 parent 4ef7ea3 commit cab9bff

File tree

2 files changed

+47
-88
lines changed

2 files changed

+47
-88
lines changed

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

Lines changed: 45 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import java.util.LinkedList;
2727
import java.util.List;
2828
import java.util.Map;
29-
import java.util.Queue;
3029
import java.util.Set;
3130
import java.util.function.BiConsumer;
3231
import java.util.stream.Collectors;
@@ -302,7 +301,7 @@ private class Loader {
302301

303302
private final List<PropertySourceLoader> propertySourceLoaders;
304303

305-
private Queue<Profile> profiles;
304+
private LinkedList<Profile> profiles;
306305

307306
private List<Profile> processedProfiles;
308307

@@ -321,7 +320,7 @@ private class Loader {
321320
}
322321

323322
public void load() {
324-
this.profiles = Collections.asLifoQueue(new LinkedList<Profile>());
323+
this.profiles = new LinkedList<>();
325324
this.processedProfiles = new LinkedList<>();
326325
this.activatedProfiles = false;
327326
this.loaded = new LinkedHashMap<>();
@@ -343,62 +342,62 @@ public void load() {
343342
* properties that are already set.
344343
*/
345344
private void initializeProfiles() {
346-
Set<Profile> initialActiveProfiles = initializeActiveProfiles();
347-
this.profiles.addAll(getUnprocessedActiveProfiles(initialActiveProfiles));
348-
if (this.profiles.isEmpty()) {
345+
//The default profile for these purposes is represented as null. We add it
346+
// first so that it is processed first and has lowest priority.
347+
this.profiles.add(null);
348+
Set<Profile> activatedViaProperty = getProfilesActivatedViaActiveProfileProperty();
349+
processOtherActiveProfiles(activatedViaProperty);
350+
// Any pre-existing active activeProfiles set via property sources (e.g. System
351+
// properties) take precedence over those added in config files.
352+
addActiveProfiles(activatedViaProperty);
353+
if (this.profiles.size() == 1) { //only has null profile
349354
for (String defaultProfileName : this.environment.getDefaultProfiles()) {
350-
Profile defaultProfile = new Profile(defaultProfileName, true);
351-
if (!this.profiles.contains(defaultProfile)) {
352-
this.profiles.add(defaultProfile);
353-
}
355+
ConfigFileApplicationListener.Profile defaultProfile = new ConfigFileApplicationListener.Profile(
356+
defaultProfileName, true);
357+
this.profiles.add(defaultProfile);
354358
}
355359
}
356-
// The default profile for these purposes is represented as null. We add it
357-
// last so that it is first out of the queue (active profiles will then
358-
// override any settings in the defaults when the list is reversed later).
359-
this.profiles.add(null);
360360
}
361361

362-
private Set<Profile> initializeActiveProfiles() {
362+
private Set<Profile> getProfilesActivatedViaActiveProfileProperty() {
363363
if (!this.environment.containsProperty(ACTIVE_PROFILES_PROPERTY)
364364
&& !this.environment.containsProperty(INCLUDE_PROFILES_PROPERTY)) {
365365
return Collections.emptySet();
366366
}
367-
// Any pre-existing active profiles set via property sources (e.g. System
368-
// properties) take precedence over those added in config files.
369367
Binder binder = Binder.get(this.environment);
370368
Set<Profile> activeProfiles = new LinkedHashSet<>();
371369
activeProfiles.addAll(getProfiles(binder, ACTIVE_PROFILES_PROPERTY));
372370
activeProfiles.addAll(getProfiles(binder, INCLUDE_PROFILES_PROPERTY));
373-
maybeActivateProfiles(activeProfiles);
374371
return activeProfiles;
375372
}
376373

377-
/**
378-
* Return the active profiles that have not been processed yet. If a profile is
379-
* enabled via both {@link #ACTIVE_PROFILES_PROPERTY} and
380-
* {@link ConfigurableEnvironment#addActiveProfile(String)} it needs to be
381-
* filtered so that the {@link #ACTIVE_PROFILES_PROPERTY} value takes precedence.
382-
* <p>
383-
* Concretely, if the "cloud" profile is enabled via the environment, it will take
384-
* less precedence that any profile set via the {@link #ACTIVE_PROFILES_PROPERTY}.
385-
* @param initialActiveProfiles the profiles that have been enabled via
386-
* {@link #ACTIVE_PROFILES_PROPERTY}
387-
* @return the unprocessed active profiles from the environment to enable
388-
*/
389-
private List<Profile> getUnprocessedActiveProfiles(
390-
Set<Profile> initialActiveProfiles) {
391-
List<Profile> unprocessedActiveProfiles = new ArrayList<>();
392-
for (String profileName : this.environment.getActiveProfiles()) {
393-
Profile profile = new Profile(profileName);
394-
if (!initialActiveProfiles.contains(profile)) {
395-
unprocessedActiveProfiles.add(profile);
396-
}
374+
private void processOtherActiveProfiles(Set<Profile> activatedViaProperty) {
375+
List<Profile> otherActiveProfiles = Arrays.stream(this.environment.getActiveProfiles())
376+
.map(Profile::new)
377+
.filter(o -> !activatedViaProperty.contains(o)).collect(Collectors.toList());
378+
this.profiles.addAll(otherActiveProfiles);
379+
}
380+
381+
void addActiveProfiles(Set<Profile> profiles) {
382+
if (this.activatedProfiles || profiles.isEmpty()) {
383+
return;
397384
}
398-
// Reverse them so the order is the same as from getProfilesForValue()
399-
// (last one wins when properties are eventually resolved)
400-
Collections.reverse(unprocessedActiveProfiles);
401-
return unprocessedActiveProfiles;
385+
addProfiles(profiles);
386+
this.logger.debug("Activated activeProfiles "
387+
+ StringUtils.collectionToCommaDelimitedString(profiles));
388+
this.activatedProfiles = true;
389+
removeUnprocessedDefaultProfiles();
390+
}
391+
392+
void addProfiles(Set<Profile> profiles) {
393+
for (Profile profile : profiles) {
394+
this.profiles.add(profile);
395+
addProfileToEnvironment(profile.getName());
396+
}
397+
}
398+
399+
private void removeUnprocessedDefaultProfiles() {
400+
this.profiles.removeIf(profile -> (profile != null && profile.isDefaultProfile()));
402401
}
403402

404403
private DocumentFilter getPositiveProfileFilter(Profile profile) {
@@ -520,7 +519,7 @@ private void load(PropertySourceLoader loader, String location, Profile profile,
520519
List<Document> loaded = new ArrayList<>();
521520
for (Document document : documents) {
522521
if (filter.match(document)) {
523-
maybeActivateProfiles(document.getActiveProfiles());
522+
addActiveProfiles(document.getActiveProfiles());
524523
addProfiles(document.getIncludeProfiles());
525524
loaded.add(document);
526525
}
@@ -587,58 +586,16 @@ private Set<Profile> asProfileSet(String[] profileNames) {
587586
for (String profileName : profileNames) {
588587
profiles.add(new Profile(profileName));
589588
}
590-
Collections.reverse(profiles);
591589
return new LinkedHashSet<>(profiles);
592590
}
593591

594-
private void maybeActivateProfiles(Set<Profile> profiles) {
595-
if (profiles.isEmpty()) {
596-
return;
597-
}
598-
if (this.activatedProfiles) {
599-
this.logger.debug("Profiles already activated, '" + profiles
600-
+ "' will not be applied");
601-
return;
602-
}
603-
addProfiles(profiles);
604-
this.logger.debug("Activated profiles "
605-
+ StringUtils.collectionToCommaDelimitedString(profiles));
606-
this.activatedProfiles = true;
607-
removeUnprocessedDefaultProfiles();
608-
}
609-
610-
private void removeUnprocessedDefaultProfiles() {
611-
this.profiles.removeIf(Profile::isDefaultProfile);
612-
}
613-
614-
private void addProfiles(Set<Profile> profiles) {
615-
for (Profile profile : profiles) {
616-
this.profiles.add(profile);
617-
if (!environmentHasActiveProfile(profile.getName())) {
618-
// If it's already accepted we assume the order was set
619-
// intentionally
620-
prependProfile(this.environment, profile);
621-
}
622-
}
623-
}
624-
625-
private boolean environmentHasActiveProfile(String profile) {
592+
private void addProfileToEnvironment(String profile) {
626593
for (String activeProfile : this.environment.getActiveProfiles()) {
627594
if (activeProfile.equals(profile)) {
628-
return true;
595+
return;
629596
}
630597
}
631-
return false;
632-
}
633-
634-
private void prependProfile(ConfigurableEnvironment environment,
635-
Profile profile) {
636-
Set<String> profiles = new LinkedHashSet<>();
637-
environment.getActiveProfiles(); // ensure they are initialized
638-
// But this one should go first (last wins in a property key clash)
639-
profiles.add(profile.getName());
640-
profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
641-
environment.setActiveProfiles(StringUtils.toStringArray(profiles));
598+
this.environment.addActiveProfile(profile);
642599
}
643600

644601
private Set<String> getSearchLocations() {

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,8 @@ public void activateProfileFromProfileSpecificProperties() {
758758
assertThat(environment).has(matchingProfile("morespecific"));
759759
assertThat(environment).has(matchingProfile("yetmorespecific"));
760760
assertThat(environment).doesNotHave(matchingProfile("missing"));
761+
assertThat(this.out.toString())
762+
.contains("The following profiles are active: includeprofile,specific,morespecific,yetmorespecific");
761763
}
762764

763765
@Test

0 commit comments

Comments
 (0)