Support profile expression in yml profile matching

Closes gh-12469
This commit is contained in:
Stephane Nicoll
2018-06-15 16:29:40 +02:00
parent 0c4176f596
commit a89b2ae46e
7 changed files with 90 additions and 33 deletions

View File

@@ -756,15 +756,25 @@ example:
address: 127.0.0.1
---
spring:
profiles: production
profiles: production & eu-central
server:
address: 192.168.1.120
----
In the preceding example, if the `development` profile is active, the `server.address`
property is `127.0.0.1`. Similarly, if the `production` profile is active, the
`server.address` property is `192.168.1.120`. If the `development` and `production`
profiles are *not* enabled, then the value for the property is `192.168.1.100`.
property is `127.0.0.1`. Similarly, if the `production` *and* `eu-central` profiles are
active, the `server.address` property is `192.168.1.120`. If the `development` and
`production` and `eu-central` profiles are *not* enabled, then the value for the property
is `192.168.1.100`.
[NOTE]
====
`spring.profiles` can therefore contains a simple profile name (for example `production`)
or a profile expression. A profile expression allows for more complicated profile logic
to be expressed, for example `production & (eu-central | eu-west)`. Check the
{spring-reference}core.html#beans-definition-profiles-java[reference guide] for more
details.
====
If none are explicitly active when the application context starts, the default profiles
are activated. So, in the following YAML, we set a value for `spring.security.user.password`

View File

@@ -57,6 +57,7 @@ import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.Profiles;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
@@ -411,14 +412,15 @@ public class ConfigFileApplicationListener
}
return ObjectUtils.containsElement(document.getProfiles(),
profile.getName())
&& this.environment.acceptsProfiles(document.getProfiles());
&& this.environment
.acceptsProfiles(Profiles.of(document.getProfiles()));
};
}
private DocumentFilter getNegativeProfileFilter(Profile profile) {
return (Document document) -> (profile == null
&& !ObjectUtils.isEmpty(document.getProfiles())
&& this.environment.acceptsProfiles(document.getProfiles()));
&& !ObjectUtils.isEmpty(document.getProfiles()) && this.environment
.acceptsProfiles(Profiles.of(document.getProfiles())));
}
private DocumentConsumer addToLoaded(

View File

@@ -21,6 +21,7 @@ import org.junit.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Profiles;
import static org.assertj.core.api.Assertions.assertThat;
@@ -50,8 +51,10 @@ public class ReproTests {
this.context = application.run(
"--spring.config.name=enableprofileviaapplicationproperties",
"--spring.profiles.active=dev");
assertThat(this.context.getEnvironment().acceptsProfiles("dev")).isTrue();
assertThat(this.context.getEnvironment().acceptsProfiles("a")).isTrue();
assertThat(this.context.getEnvironment().acceptsProfiles(Profiles.of("dev")))
.isTrue();
assertThat(this.context.getEnvironment().acceptsProfiles(Profiles.of("a")))
.isTrue();
}
@Test

View File

@@ -83,6 +83,7 @@ import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.Profiles;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.ClassPathResource;
@@ -525,7 +526,7 @@ public class SpringApplicationTests {
ConfigurableEnvironment environment = new StandardEnvironment();
application.setEnvironment(environment);
this.context = application.run();
assertThat(environment.acceptsProfiles("foo")).isTrue();
assertThat(environment.acceptsProfiles(Profiles.of("foo"))).isTrue();
}
@Test

View File

@@ -31,6 +31,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Profiles;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
@@ -72,7 +73,8 @@ public class SpringApplicationBuilderTests {
this.context = application.run();
assertThat(this.context).isInstanceOf(StaticApplicationContext.class);
assertThat(this.context.getEnvironment().getProperty("foo")).isEqualTo("bucket");
assertThat(this.context.getEnvironment().acceptsProfiles("foo")).isTrue();
assertThat(this.context.getEnvironment().acceptsProfiles(Profiles.of("foo")))
.isTrue();
}
@Test
@@ -205,11 +207,12 @@ public class SpringApplicationBuilderTests {
ExampleConfig.class).profiles("node").properties("transport=redis")
.child(ChildConfig.class).web(WebApplicationType.NONE);
this.context = application.run();
assertThat(this.context.getEnvironment().acceptsProfiles("node")).isTrue();
assertThat(this.context.getEnvironment().acceptsProfiles(Profiles.of("node")))
.isTrue();
assertThat(this.context.getEnvironment().getProperty("transport"))
.isEqualTo("redis");
assertThat(this.context.getParent().getEnvironment().acceptsProfiles("node"))
.isTrue();
assertThat(this.context.getParent().getEnvironment()
.acceptsProfiles(Profiles.of("node"))).isTrue();
assertThat(this.context.getParent().getEnvironment().getProperty("transport"))
.isEqualTo("redis");
// only defined in node profile
@@ -223,10 +226,10 @@ public class SpringApplicationBuilderTests {
.child(ChildConfig.class).profiles("admin")
.web(WebApplicationType.NONE);
this.context = application.run();
assertThat(this.context.getEnvironment().acceptsProfiles("node", "admin"))
.isTrue();
assertThat(this.context.getParent().getEnvironment().acceptsProfiles("admin"))
.isFalse();
assertThat(this.context.getEnvironment()
.acceptsProfiles(Profiles.of("node", "admin"))).isTrue();
assertThat(this.context.getParent().getEnvironment()
.acceptsProfiles(Profiles.of("admin"))).isFalse();
}
@Test
@@ -237,12 +240,12 @@ public class SpringApplicationBuilderTests {
.profiles("admin").web(WebApplicationType.NONE);
shared.profiles("parent");
this.context = application.run();
assertThat(this.context.getEnvironment().acceptsProfiles("node", "admin"))
.isTrue();
assertThat(this.context.getParent().getEnvironment().acceptsProfiles("node",
"parent")).isTrue();
assertThat(this.context.getParent().getEnvironment().acceptsProfiles("admin"))
.isFalse();
assertThat(this.context.getEnvironment()
.acceptsProfiles(Profiles.of("node", "admin"))).isTrue();
assertThat(this.context.getParent().getEnvironment()
.acceptsProfiles(Profiles.of("node", "parent"))).isTrue();
assertThat(this.context.getParent().getEnvironment()
.acceptsProfiles(Profiles.of("admin"))).isFalse();
}
@Test
@@ -253,12 +256,12 @@ public class SpringApplicationBuilderTests {
.child(ChildConfig.class).profiles("admin")
.web(WebApplicationType.NONE);
this.context = application.run();
assertThat(this.context.getEnvironment().acceptsProfiles("node", "admin"))
.isTrue();
assertThat(this.context.getEnvironment()
.acceptsProfiles(Profiles.of("node", "admin"))).isTrue();
// Now they share an Environment explicitly so there's no way to keep the profiles
// separate
assertThat(this.context.getParent().getEnvironment().acceptsProfiles("admin"))
.isTrue();
assertThat(this.context.getParent().getEnvironment()
.acceptsProfiles(Profiles.of("admin"))).isTrue();
}
@Test

View File

@@ -54,6 +54,7 @@ import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.Profiles;
import org.springframework.core.env.SimpleCommandLinePropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.ByteArrayResource;
@@ -504,6 +505,29 @@ public class ConfigFileApplicationListenerTests {
assertThat(property).isEqualTo("notempty");
}
@Test
public void yamlProfileExpressionsAnd() {
assertProfileExpression("devandother", "dev", "other");
}
@Test
public void yamlProfileExpressionsComplex() {
assertProfileExpression("devorotherandanother", "dev", "another");
}
@Test
public void yamlProfileExpressionsNoMatch() {
assertProfileExpression("fromyamlfile", "dev");
}
private void assertProfileExpression(String value, String... activeProfiles) {
this.environment.setActiveProfiles(activeProfiles);
this.initializer.setSearchNames("testprofileexpression");
this.initializer.postProcessEnvironment(this.environment, this.application);
String property = this.environment.getProperty("my.property");
assertThat(property).isEqualTo(value);
}
@Test
public void yamlNegatedProfiles() {
// gh-8011
@@ -827,7 +851,7 @@ public class ConfigFileApplicationListenerTests {
assertThat(environment.containsProperty("customprofile")).isTrue();
assertThat(environment.containsProperty("customprofile-specific")).isTrue();
assertThat(environment.containsProperty("customprofile-customdefault")).isTrue();
assertThat(environment.acceptsProfiles("customdefault")).isTrue();
assertThat(environment.acceptsProfiles(Profiles.of("customdefault"))).isTrue();
}
@Test
@@ -899,7 +923,7 @@ public class ConfigFileApplicationListenerTests {
application.setWebApplicationType(WebApplicationType.NONE);
this.context = application.run("--spring.config.name=applicationloop");
ConfigurableEnvironment environment = this.context.getEnvironment();
assertThat(environment.acceptsProfiles("loop")).isTrue();
assertThat(environment.acceptsProfiles(Profiles.of("loop"))).isTrue();
}
@Test
@@ -909,8 +933,8 @@ public class ConfigFileApplicationListenerTests {
application.setWebApplicationType(WebApplicationType.NONE);
this.context = application.run("--spring.config.name=applicationmultiprofiles");
ConfigurableEnvironment environment = this.context.getEnvironment();
assertThat(environment.acceptsProfiles("test")).isTrue();
assertThat(environment.acceptsProfiles("another-test")).isTrue();
assertThat(environment.acceptsProfiles(Profiles.of("test"))).isTrue();
assertThat(environment.acceptsProfiles(Profiles.of("another-test"))).isTrue();
assertThat(environment.getProperty("message")).isEqualTo("multiprofile");
}
@@ -932,7 +956,7 @@ public class ConfigFileApplicationListenerTests {
@Override
public boolean matches(ConfigurableEnvironment value) {
return value.acceptsProfiles(profile);
return value.acceptsProfiles(Profiles.of(profile));
}
};

View File

@@ -0,0 +1,14 @@
---
my:
property: fromyamlfile
---
spring:
profiles: dev & other
my:
property: devandother
---
spring:
profiles: (dev | other) & another
my:
property: devorotherandanother
---