mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-08-29 03:06:45 +08:00
Add support for profile groups
Add support for profile groups so that users can combine a number of fine-grained profiles into a single logical group. Closes gh-22522
This commit is contained in:
parent
8c6c4fa9fa
commit
eee260fc03
@ -1711,6 +1711,27 @@ For example, when an application with the following properties is run by using t
|
||||
|
||||
|
||||
|
||||
[[boot-features-profiles-groups]]
|
||||
=== Profile Groups
|
||||
Occasionally the profiles that you define and use in your application are too fine-grained and become cumbersome to use.
|
||||
For example, you might have `proddb` and `prodmq` profiles that you use to enable database and messaging features independently.
|
||||
|
||||
To help with this, Spring Boot lets you define profile groups.
|
||||
A profile group allows you to define a logical name for a related group of profiles.
|
||||
|
||||
For example, we can create a `production` group that consists of our `proddb` and `prodmq` profiles.
|
||||
|
||||
[source,yaml,indent=0]
|
||||
----
|
||||
spring.profiles.group.production:
|
||||
- proddb
|
||||
- prodmq
|
||||
----
|
||||
|
||||
Our application can now be started using `--spring.profiles.active=production` to active the `production`, `proddb` and `prodmq` profiles in one hit.
|
||||
|
||||
|
||||
|
||||
[[boot-features-programmatically-setting-profiles]]
|
||||
=== Programmatically Setting Profiles
|
||||
You can programmatically set active profiles by calling `SpringApplication.setAdditionalProfiles(...)` before your application runs.
|
||||
|
@ -28,11 +28,15 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.boot.context.properties.bind.Bindable;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.env.AbstractEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@ -45,10 +49,15 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public class Profiles implements Iterable<String> {
|
||||
|
||||
private static final Bindable<MultiValueMap<String, String>> STRING_STRINGS_MAP = Bindable
|
||||
.of(ResolvableType.forClassWithGenerics(MultiValueMap.class, String.class, String.class));
|
||||
|
||||
private static final Set<String> UNSET_ACTIVE = Collections.emptySet();
|
||||
|
||||
private static final Set<String> UNSET_DEFAULT = Collections.singleton("default");
|
||||
|
||||
private final MultiValueMap<String, String> groups;
|
||||
|
||||
private final List<String> activeProfiles;
|
||||
|
||||
private final List<String> defaultProfiles;
|
||||
@ -63,6 +72,7 @@ public class Profiles implements Iterable<String> {
|
||||
* @param additionalProfiles and additional active profiles
|
||||
*/
|
||||
Profiles(Environment environment, Binder binder, Collection<String> additionalProfiles) {
|
||||
this.groups = binder.bind("spring.profiles.group", STRING_STRINGS_MAP).orElseGet(LinkedMultiValueMap::new);
|
||||
this.activeProfiles = asUniqueItemList(get(environment, binder, environment::getActiveProfiles,
|
||||
AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME, UNSET_ACTIVE), additionalProfiles);
|
||||
this.defaultProfiles = asUniqueItemList(get(environment, binder, environment::getDefaultProfiles,
|
||||
@ -94,7 +104,9 @@ public class Profiles implements Iterable<String> {
|
||||
asReversedList((!activeProfiles.isEmpty()) ? activeProfiles : defaultProfiles).forEach(stack::push);
|
||||
Set<String> acceptedProfiles = new LinkedHashSet<>();
|
||||
while (!stack.isEmpty()) {
|
||||
acceptedProfiles.add(stack.pop());
|
||||
String current = stack.pop();
|
||||
acceptedProfiles.add(current);
|
||||
asReversedList(this.groups.get(current)).forEach(stack::push);
|
||||
}
|
||||
return asUniqueItemList(StringUtils.toStringArray(acceptedProfiles));
|
||||
}
|
||||
|
@ -262,6 +262,17 @@ class ProfilesTests {
|
||||
assertThat(profiles.isAccepted("x")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void iteratorWithProfileGroups() {
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.setProperty("spring.profiles.active", "a,b,c");
|
||||
environment.setProperty("spring.profiles.group.a", "e,f");
|
||||
environment.setProperty("spring.profiles.group.e", "x,y");
|
||||
Binder binder = Binder.get(environment);
|
||||
Profiles profiles = new Profiles(environment, binder, null);
|
||||
assertThat(profiles).containsExactly("a", "e", "x", "y", "f", "b", "c");
|
||||
}
|
||||
|
||||
@Test
|
||||
void iteratorWithProfileGroupsAndNoActive() {
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
@ -272,4 +283,60 @@ class ProfilesTests {
|
||||
assertThat(profiles).containsExactly("default");
|
||||
}
|
||||
|
||||
@Test
|
||||
void iteratorWithProfileGroupsForDefault() {
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.setProperty("spring.profiles.group.default", "e,f");
|
||||
Binder binder = Binder.get(environment);
|
||||
Profiles profiles = new Profiles(environment, binder, null);
|
||||
assertThat(profiles).containsExactly("default", "e", "f");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAcceptedWithProfileGroups() {
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.setProperty("spring.profiles.active", "a,b,c");
|
||||
environment.setProperty("spring.profiles.group.a", "e,f");
|
||||
environment.setProperty("spring.profiles.group.e", "x,y");
|
||||
environment.setDefaultProfiles("g", "h", "i");
|
||||
Binder binder = Binder.get(environment);
|
||||
Profiles profiles = new Profiles(environment, binder, null);
|
||||
assertThat(profiles.getAccepted()).containsExactly("a", "e", "x", "y", "f", "b", "c");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAcceptedWhenNoActiveAndDefaultWithGroups() {
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.setDefaultProfiles("d", "e", "f");
|
||||
environment.setProperty("spring.profiles.group.e", "x,y");
|
||||
Binder binder = Binder.get(environment);
|
||||
Profiles profiles = new Profiles(environment, binder, null);
|
||||
assertThat(profiles.getAccepted()).containsExactly("d", "e", "x", "y", "f");
|
||||
}
|
||||
|
||||
@Test
|
||||
void isAcceptedWithGroupsReturnsTrue() {
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.setProperty("spring.profiles.active", "a,b,c");
|
||||
environment.setProperty("spring.profiles.group.a", "e,f");
|
||||
environment.setProperty("spring.profiles.group.e", "x,y");
|
||||
environment.setDefaultProfiles("g", "h", "i");
|
||||
Binder binder = Binder.get(environment);
|
||||
Profiles profiles = new Profiles(environment, binder, null);
|
||||
assertThat(profiles.isAccepted("a")).isTrue();
|
||||
assertThat(profiles.isAccepted("e")).isTrue();
|
||||
assertThat(profiles.isAccepted("g")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isAcceptedWhenNoActiveAndDefaultWithGroupsContainsProfileReturnsTrue() {
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.setDefaultProfiles("d", "e", "f");
|
||||
environment.setProperty("spring.profiles.group.e", "x,y");
|
||||
Binder binder = Binder.get(environment);
|
||||
Profiles profiles = new Profiles(environment, binder, null);
|
||||
assertThat(profiles.isAccepted("d")).isTrue();
|
||||
assertThat(profiles.isAccepted("x")).isTrue();
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user