Browse Source

Add application listener to locate property sources during bootstrap (#1228)

* Add application listener to locate property sources during bootstrap

Also adds support for activating profiles using spring.profiles.active from bootstrap property source listeners.

Allow profiles to be passed from bootstrap context to main application context

* Add application listener to locate property sources during bootstrap

Also adds support for activating profiles using spring.profiles.active from bootstrap property source listeners.

Allow profiles to be passed from bootstrap context to main application context

Updating version in docs
pull/1239/head
Ryan Baxter 1 year ago committed by GitHub
parent
commit
2f467e5823
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      docs/src/main/asciidoc/_configprops.adoc
  2. 10
      docs/src/main/asciidoc/spring-cloud-commons.adoc
  3. 7
      spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/BootstrapApplicationListener.java
  4. 121
      spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceBootstrapConfiguration.java
  5. 13
      spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceBootstrapProperties.java
  6. 393
      spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/config/BootstrapConfigurationTests.java

1
docs/src/main/asciidoc/_configprops.adoc

@ -4,6 +4,7 @@
|spring.cloud.compatibility-verifier.compatible-boot-versions | | Default accepted versions for the Spring Boot dependency. You can set {@code x} for the patch version if you don't want to specify a concrete value. Example: {@code 3.4.x} |spring.cloud.compatibility-verifier.compatible-boot-versions | | Default accepted versions for the Spring Boot dependency. You can set {@code x} for the patch version if you don't want to specify a concrete value. Example: {@code 3.4.x}
|spring.cloud.compatibility-verifier.enabled | `+++false+++` | Enables creation of Spring Cloud compatibility verification. |spring.cloud.compatibility-verifier.enabled | `+++false+++` | Enables creation of Spring Cloud compatibility verification.
|spring.cloud.config.allow-override | `+++true+++` | Flag to indicate that {@link #isOverrideSystemProperties() systemPropertiesOverride} can be used. Set to false to prevent users from changing the default accidentally. Default true. |spring.cloud.config.allow-override | `+++true+++` | Flag to indicate that {@link #isOverrideSystemProperties() systemPropertiesOverride} can be used. Set to false to prevent users from changing the default accidentally. Default true.
|spring.cloud.config.initialize-on-context-refresh | `+++false+++` | Flag to initialize bootstrap configuration on context refresh event. Default false.
|spring.cloud.config.override-none | `+++false+++` | Flag to indicate that when {@link #setAllowOverride(boolean) allowOverride} is true, external properties should take lowest priority and should not override any existing property sources (including local config files). Default false. |spring.cloud.config.override-none | `+++false+++` | Flag to indicate that when {@link #setAllowOverride(boolean) allowOverride} is true, external properties should take lowest priority and should not override any existing property sources (including local config files). Default false.
|spring.cloud.config.override-system-properties | `+++true+++` | Flag to indicate that the external properties should override system properties. Default true. |spring.cloud.config.override-system-properties | `+++true+++` | Flag to indicate that the external properties should override system properties. Default true.
|spring.cloud.decrypt-environment-post-processor.enabled | `+++true+++` | Enable the DecryptEnvironmentPostProcessor. |spring.cloud.decrypt-environment-post-processor.enabled | `+++true+++` | Enable the DecryptEnvironmentPostProcessor.

10
docs/src/main/asciidoc/spring-cloud-commons.adoc

@ -54,6 +54,10 @@ The additional property sources are:
An example would be properties from the Spring Cloud Config Server. An example would be properties from the Spring Cloud Config Server.
See "`<<customizing-bootstrap-property-sources>>`" for how to customize the contents of this property source. See "`<<customizing-bootstrap-property-sources>>`" for how to customize the contents of this property source.
NOTE: Prior to Spring Cloud 2021.0.7 `PropertySourceLocators` (including the ones for Spring Cloud Config) were run during
the main application context and not in the Bootstrap context. You can force `PropertySourceLocators` to be run during the
Bootstrap context by setting `spring.cloud.config.initialize-on-context-refresh=true` in `bootstrap.[properties | yaml]`.
* "`applicationConfig: [classpath:bootstrap.yml]`" (and related files if Spring profiles are active): If you have a `bootstrap.yml` (or `.properties`), those properties are used to configure the bootstrap context. * "`applicationConfig: [classpath:bootstrap.yml]`" (and related files if Spring profiles are active): If you have a `bootstrap.yml` (or `.properties`), those properties are used to configure the bootstrap context.
Then they get added to the child context when its parent is set. Then they get added to the child context when its parent is set.
They have lower precedence than the `application.yml` (or `.properties`) and any other property sources that are added to the child as a normal part of the process of creating a Spring Boot application. They have lower precedence than the `application.yml` (or `.properties`) and any other property sources that are added to the child as a normal part of the process of creating a Spring Boot application.
@ -146,6 +150,12 @@ org.springframework.cloud.bootstrap.BootstrapConfiguration=sample.custom.CustomP
---- ----
==== ====
As of Spring Cloud 2021.0.8, Spring Cloud will now call `PropertySourceLocators` twice. The first fetch
will retrieve any property sources without any profiles. These property sources will have the opportunity to
activate profiles using `spring.profiles.active`. After the main application context starts `PropertySourceLocators`
will be called a second time, this time with any active profiles allowing `PropertySourceLocators` to locate
any additional `PropertySources` with profiles.
=== Logging Configuration === Logging Configuration
If you use Spring Boot to configure log settings, you should place this configuration in `bootstrap.[yml | properties]` if you would like it to apply to all events. If you use Spring Boot to configure log settings, you should place this configuration in `bootstrap.[yml | properties]` if you would like it to apply to all events.

7
spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/BootstrapApplicationListener.java

@ -294,6 +294,13 @@ public class BootstrapApplicationListener implements ApplicationListener<Applica
target.addAll(getOrderedBeansOfType(context, ApplicationContextInitializer.class)); target.addAll(getOrderedBeansOfType(context, ApplicationContextInitializer.class));
application.setInitializers(target); application.setInitializers(target);
addBootstrapDecryptInitializer(application); addBootstrapDecryptInitializer(application);
// Get the active profiles from the bootstrap context and set them in main
// application
// environment. This allows any profiles activated during bootstrap to be
// activated when
// config data runs in the main application context.
environment.setActiveProfiles(context.getEnvironment().getActiveProfiles());
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

121
spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceBootstrapConfiguration.java

@ -17,18 +17,20 @@
package org.springframework.cloud.bootstrap.config; package org.springframework.cloud.bootstrap.config;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.stream.Collectors;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.config.ConfigFileApplicationListener; import org.springframework.boot.context.config.Profiles;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.bind.Bindable; import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder; import org.springframework.boot.context.properties.bind.Binder;
@ -39,8 +41,10 @@ import org.springframework.cloud.bootstrap.BootstrapApplicationListener;
import org.springframework.cloud.context.environment.EnvironmentChangeEvent; import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.cloud.logging.LoggingRebinder; import org.springframework.cloud.logging.LoggingRebinder;
import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.env.AbstractEnvironment; import org.springframework.core.env.AbstractEnvironment;
@ -52,6 +56,7 @@ import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource; import org.springframework.core.env.PropertySource;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import static org.springframework.cloud.bootstrap.encrypt.AbstractEnvironmentDecrypt.DECRYPTED_PROPERTY_SOURCE_NAME;
import static org.springframework.core.env.StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME; import static org.springframework.core.env.StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME;
/** /**
@ -60,8 +65,8 @@ import static org.springframework.core.env.StandardEnvironment.SYSTEM_ENVIRONMEN
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(PropertySourceBootstrapProperties.class) @EnableConfigurationProperties(PropertySourceBootstrapProperties.class)
public class PropertySourceBootstrapConfiguration public class PropertySourceBootstrapConfiguration implements ApplicationListener<ContextRefreshedEvent>,
implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered { ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
/** /**
* Bootstrap property source name. * Bootstrap property source name.
@ -76,6 +81,9 @@ public class PropertySourceBootstrapConfiguration
@Autowired(required = false) @Autowired(required = false)
private List<PropertySourceLocator> propertySourceLocators = new ArrayList<>(); private List<PropertySourceLocator> propertySourceLocators = new ArrayList<>();
@Autowired
private PropertySourceBootstrapProperties bootstrapProperties;
@Override @Override
public int getOrder() { public int getOrder() {
return this.order; return this.order;
@ -85,8 +93,25 @@ public class PropertySourceBootstrapConfiguration
this.propertySourceLocators = new ArrayList<>(propertySourceLocators); this.propertySourceLocators = new ArrayList<>(propertySourceLocators);
} }
/*
* The ApplicationListener is called when the main application context is initialized.
* This will be called after the ApplicationListener ContextRefreshedEvent is fired
* during the bootstrap phase. This method is also what added PropertySources prior to
* Spring Cloud 2021.0.7, this is why it will be called when
* spring.cloud.config.initialize-on-context-refresh is false. When
* spring.cloud.config.initialize-on-context-refresh is true this method provides a
* "second fetch" of configuration data to fetch any additional configuration data
* from profiles that have been activated.
*/
@Override @Override
public void initialize(ConfigurableApplicationContext applicationContext) { public void initialize(ConfigurableApplicationContext applicationContext) {
if (!bootstrapProperties.isInitializeOnContextRefresh() || !applicationContext.getEnvironment()
.getPropertySources().contains(BootstrapApplicationListener.BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
doInitialize(applicationContext);
}
}
private void doInitialize(ConfigurableApplicationContext applicationContext) {
List<PropertySource<?>> composite = new ArrayList<>(); List<PropertySource<?>> composite = new ArrayList<>();
AnnotationAwareOrderComparator.sort(this.propertySourceLocators); AnnotationAwareOrderComparator.sort(this.propertySourceLocators);
boolean empty = true; boolean empty = true;
@ -122,7 +147,7 @@ public class PropertySourceBootstrapConfiguration
insertPropertySources(propertySources, composite); insertPropertySources(propertySources, composite);
reinitializeLoggingSystem(environment, logConfig, logFile); reinitializeLoggingSystem(environment, logConfig, logFile);
setLogLevels(applicationContext, environment); setLogLevels(applicationContext, environment);
handleIncludedProfiles(environment); handleProfiles(environment);
} }
} }
@ -172,7 +197,12 @@ public class PropertySourceBootstrapConfiguration
if (!remoteProperties.isAllowOverride() if (!remoteProperties.isAllowOverride()
|| (!remoteProperties.isOverrideNone() && remoteProperties.isOverrideSystemProperties())) { || (!remoteProperties.isOverrideNone() && remoteProperties.isOverrideSystemProperties())) {
for (PropertySource<?> p : reversedComposite) { for (PropertySource<?> p : reversedComposite) {
propertySources.addFirst(p); if (propertySources.contains(DECRYPTED_PROPERTY_SOURCE_NAME)) {
propertySources.addAfter(DECRYPTED_PROPERTY_SOURCE_NAME, p);
}
else {
propertySources.addFirst(p);
}
} }
return; return;
} }
@ -210,43 +240,98 @@ public class PropertySourceBootstrapConfiguration
return environment; return environment;
} }
private void handleIncludedProfiles(ConfigurableEnvironment environment) { private void handleProfiles(ConfigurableEnvironment environment) {
if (bootstrapProperties.isInitializeOnContextRefresh() && !environment.getPropertySources()
.contains(BootstrapApplicationListener.BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
// In the case that spring.cloud.config.initialize-on-context-refresh is true
// this method will
// be called during the bootstrap phase and the main application startup. We
// only manipulate the environment profiles in the bootstrap phase as we are
// fetching
// any additional profile specific configuration when this method would be
// called during the
// main application startup, and it is not valid to activate profiles in
// profile specific
// configuration properties, so we should not run this method then.
return;
}
Set<String> includeProfiles = new TreeSet<>(); Set<String> includeProfiles = new TreeSet<>();
List<String> activeProfiles = new ArrayList<>();
for (PropertySource<?> propertySource : environment.getPropertySources()) { for (PropertySource<?> propertySource : environment.getPropertySources()) {
addIncludedProfilesTo(includeProfiles, propertySource); addIncludedProfilesTo(includeProfiles, propertySource, environment);
addActiveProfilesTo(activeProfiles, propertySource, environment);
} }
List<String> activeProfiles = new ArrayList<>();
Collections.addAll(activeProfiles, environment.getActiveProfiles());
// If it's already accepted we assume the order was set intentionally // If it's already accepted we assume the order was set intentionally
includeProfiles.removeAll(activeProfiles); includeProfiles.removeAll(activeProfiles);
if (includeProfiles.isEmpty()) {
return;
}
// Prepend each added profile (last wins in a property key clash) // Prepend each added profile (last wins in a property key clash)
for (String profile : includeProfiles) { for (String profile : includeProfiles) {
activeProfiles.add(0, profile); activeProfiles.add(0, profile);
} }
List<String> activeProfilesFromEnvironment = Arrays.stream(environment.getActiveProfiles())
.collect(Collectors.toList());
if (!activeProfiles.containsAll(activeProfilesFromEnvironment)) {
activeProfiles.addAll(activeProfilesFromEnvironment);
}
environment.setActiveProfiles(activeProfiles.toArray(new String[activeProfiles.size()])); environment.setActiveProfiles(activeProfiles.toArray(new String[activeProfiles.size()]));
} }
private Set<String> addIncludedProfilesTo(Set<String> profiles, PropertySource<?> propertySource) { private Set<String> addIncludedProfilesTo(Set<String> profiles, PropertySource<?> propertySource,
ConfigurableEnvironment environment) {
return addProfilesTo(profiles, propertySource, Profiles.INCLUDE_PROFILES_PROPERTY_NAME, environment);
}
private List<String> addActiveProfilesTo(List<String> profiles, PropertySource<?> propertySource,
ConfigurableEnvironment environment) {
return addProfilesTo(profiles, propertySource, AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME, environment);
}
private <T extends Collection<String>> T addProfilesTo(T profiles, PropertySource<?> propertySource,
String property, ConfigurableEnvironment environment) {
if (propertySource instanceof CompositePropertySource) { if (propertySource instanceof CompositePropertySource) {
for (PropertySource<?> nestedPropertySource : ((CompositePropertySource) propertySource) for (PropertySource<?> nestedPropertySource : ((CompositePropertySource) propertySource)
.getPropertySources()) { .getPropertySources()) {
addIncludedProfilesTo(profiles, nestedPropertySource); addProfilesTo(profiles, nestedPropertySource, property, environment);
} }
} }
else { else {
Collections.addAll(profiles, getProfilesForValue( Collections.addAll(profiles, getProfilesForValue(propertySource.getProperty(property), environment));
propertySource.getProperty(ConfigFileApplicationListener.INCLUDE_PROFILES_PROPERTY)));
} }
return profiles; return profiles;
} }
private String[] getProfilesForValue(Object property) { private String[] getProfilesForValue(Object property, ConfigurableEnvironment environment) {
final String value = (property == null ? null : property.toString()); final String value = (property == null ? null : property.toString());
return property == null ? new String[0] : StringUtils.tokenizeToStringArray(value, ","); return property == null ? new String[0] : resolvePlaceholdersInProfiles(value, environment);
}
private String[] resolvePlaceholdersInProfiles(String profiles, ConfigurableEnvironment environment) {
return Arrays.stream(StringUtils.tokenizeToStringArray(profiles, ",")).map(s -> {
if (s.startsWith("${") && s.endsWith("}")) {
return environment.resolvePlaceholders(s);
}
else {
return s;
}
}).toArray(String[]::new);
}
/*
* The ConextRefreshedEvent gets called at the end of the boostrap phase after config
* data is loaded during bootstrap. This will run and do an "initial fetch" of
* configuration data during bootstrap but before the main applicaiton context starts.
*/
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (bootstrapProperties.isInitializeOnContextRefresh()
&& event.getApplicationContext() instanceof ConfigurableApplicationContext) {
if (((ConfigurableApplicationContext) event.getApplicationContext()).getEnvironment().getPropertySources()
.contains(BootstrapApplicationListener.BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
doInitialize((ConfigurableApplicationContext) event.getApplicationContext());
}
}
} }
} }

13
spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceBootstrapProperties.java

@ -46,6 +46,19 @@ public class PropertySourceBootstrapProperties {
*/ */
private boolean overrideNone = false; private boolean overrideNone = false;
/**
* Flag to initialize bootstrap configuration on context refresh event. Default false.
*/
private boolean initializeOnContextRefresh = false;
public boolean isInitializeOnContextRefresh() {
return initializeOnContextRefresh;
}
public void setInitializeOnContextRefresh(boolean initializeOnContextRefresh) {
this.initializeOnContextRefresh = initializeOnContextRefresh;
}
public boolean isOverrideNone() { public boolean isOverrideNone() {
return this.overrideNone; return this.overrideNone;
} }

393
spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/config/BootstrapConfigurationTests.java

@ -32,10 +32,11 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.bind.Bindable; import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder; import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.cloud.bootstrap.BootstrapApplicationListener;
import org.springframework.cloud.bootstrap.TestHigherPriorityBootstrapConfiguration; import org.springframework.cloud.bootstrap.TestHigherPriorityBootstrapConfiguration;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.AbstractEnvironment;
import org.springframework.core.env.CompositePropertySource; import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
@ -77,11 +78,20 @@ public class BootstrapConfigurationTests {
@Test @Test
public void pickupOnlyExternalBootstrapProperties() { public void pickupOnlyExternalBootstrapProperties() {
String externalPropertiesPath = getExternalProperties(); String externalPropertiesPath = getExternalProperties();
pickupOnlyExternalBootstrapProperties("spring.cloud.bootstrap.location=" + externalPropertiesPath,
"spring.config.use-legacy-processing=true");
}
@Test
public void pickupOnlyExternalBootstrapPropertiesWithAppListener() {
String externalPropertiesPath = getExternalProperties();
pickupOnlyExternalBootstrapProperties("spring.cloud.bootstrap.location=" + externalPropertiesPath,
"spring.config.use-legacy-processing=true", "spring.cloud.config.initialize-on-context-refresh=true");
}
private void pickupOnlyExternalBootstrapProperties(String... properties) {
this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(BareConfiguration.class) this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(BareConfiguration.class)
.properties("spring.cloud.bootstrap.location=" + externalPropertiesPath, .properties(properties).run();
"spring.config.use-legacy-processing=true")
.run();
then(this.context.getEnvironment().getProperty("info.name")).isEqualTo("externalPropertiesInfoName"); then(this.context.getEnvironment().getProperty("info.name")).isEqualTo("externalPropertiesInfoName");
then(this.context.getEnvironment().getProperty("info.desc")).isNull(); then(this.context.getEnvironment().getProperty("info.desc")).isNull();
then(this.context.getEnvironment().getPropertySources() then(this.context.getEnvironment().getPropertySources()
@ -92,11 +102,22 @@ public class BootstrapConfigurationTests {
@Test @Test
public void pickupAdditionalExternalBootstrapProperties() { public void pickupAdditionalExternalBootstrapProperties() {
String externalPropertiesPath = getExternalProperties(); String externalPropertiesPath = getExternalProperties();
pickupAdditionalExternalBootstrapProperties(
"spring.cloud.bootstrap.additional-location=" + externalPropertiesPath,
"spring.config.use-legacy-processing=true");
}
@Test
public void pickupAdditionalExternalBootstrapPropertiesWithAppListener() {
String externalPropertiesPath = getExternalProperties();
pickupAdditionalExternalBootstrapProperties(
"spring.cloud.bootstrap.additional-location=" + externalPropertiesPath,
"spring.config.use-legacy-processing=true", "spring.cloud.config.initialize-on-context-refresh=true");
}
private void pickupAdditionalExternalBootstrapProperties(String... properties) {
this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(BareConfiguration.class) this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(BareConfiguration.class)
.properties("spring.cloud.bootstrap.additional-location=" + externalPropertiesPath, .properties(properties).run();
"spring.config.use-legacy-processing=true")
.run();
then(this.context.getEnvironment().getProperty("info.name")).isEqualTo("externalPropertiesInfoName"); then(this.context.getEnvironment().getProperty("info.name")).isEqualTo("externalPropertiesInfoName");
then(this.context.getEnvironment().getProperty("info.desc")).isEqualTo("defaultPropertiesInfoDesc"); then(this.context.getEnvironment().getProperty("info.desc")).isEqualTo("defaultPropertiesInfoDesc");
then(this.context.getEnvironment().getPropertySources() then(this.context.getEnvironment().getPropertySources()
@ -106,14 +127,20 @@ public class BootstrapConfigurationTests {
@Test @Test
public void bootstrapPropertiesAvailableInInitializer() { public void bootstrapPropertiesAvailableInInitializer() {
this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE) bootstrapPropertiesAvailableInInitializer("spring.config.use-legacy-processing=true");
.properties("spring.config.use-legacy-processing=true").sources(BareConfiguration.class) }
.initializers(new ApplicationContextInitializer<ConfigurableApplicationContext>() {
@Override @Test
public void initialize(ConfigurableApplicationContext applicationContext) { public void bootstrapPropertiesAvailableInInitializerWithAppContext() {
// This property is defined in bootstrap.properties bootstrapPropertiesAvailableInInitializer("spring.config.use-legacy-processing=true",
then(applicationContext.getEnvironment().getProperty("info.name")).isEqualTo("child"); "spring.cloud.config.initialize-on-context-refresh=true");
} }
private void bootstrapPropertiesAvailableInInitializer(String... properties) {
this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).properties(properties)
.sources(BareConfiguration.class).initializers(applicationContext -> {
// This property is defined in bootstrap.properties
then(applicationContext.getEnvironment().getProperty("info.name")).isEqualTo("child");
}).run(); }).run();
then(this.context.getEnvironment().getPropertySources() then(this.context.getEnvironment().getPropertySources()
.contains(PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME + "-testBootstrap")) .contains(PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME + "-testBootstrap"))
@ -132,9 +159,19 @@ public class BootstrapConfigurationTests {
@Test @Test
public void picksUpAdditionalPropertySource() { public void picksUpAdditionalPropertySource() {
picksUpAdditionalPropertySource("spring.config.use-legacy-processing=true");
}
@Test
public void picksUpAdditionalPropertySourceWithAppContext() {
picksUpAdditionalPropertySource("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void picksUpAdditionalPropertySource(String... properties) {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar"); PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE) this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).properties(properties)
.properties("spring.config.use-legacy-processing=true").sources(BareConfiguration.class).run(); .sources(BareConfiguration.class).run();
then(this.context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("bar"); then(this.context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("bar");
then(this.context.getEnvironment().getPropertySources() then(this.context.getEnvironment().getPropertySources()
.contains(PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME + "-testBootstrap")) .contains(PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME + "-testBootstrap"))
@ -143,35 +180,77 @@ public class BootstrapConfigurationTests {
@Test @Test
public void failsOnPropertySource() { public void failsOnPropertySource() {
failsOnPropertySource("spring.config.use-legacy-processing=true");
}
@Test
public void failsOnPropertySourceWithAppContext() {
failsOnPropertySource("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void failsOnPropertySource(String... properties) {
System.setProperty("expected.fail", "true"); System.setProperty("expected.fail", "true");
Throwable throwable = Assertions.assertThrows(RuntimeException.class, () -> { Throwable throwable = Assertions.assertThrows(RuntimeException.class, () -> {
this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE) this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).properties(properties)
.properties("spring.config.use-legacy-processing=true").sources(BareConfiguration.class).run(); .sources(BareConfiguration.class).run();
}); });
then(throwable.getMessage().equals("Planned")); then(throwable.getMessage().equals("Planned"));
} }
@Test @Test
public void overrideSystemPropertySourceByDefault() { public void overrideSystemPropertySourceByDefault() {
overrideSystemPropertySourceByDefault("spring.config.use-legacy-processing=true");
}
@Test
public void overrideSystemPropertySourceByDefaultWithAppContext() {
overrideSystemPropertySourceByDefault("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void overrideSystemPropertySourceByDefault(String... properties) {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar"); PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
System.setProperty("bootstrap.foo", "system"); System.setProperty("bootstrap.foo", "system");
this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE) this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).properties(properties)
.properties("spring.config.use-legacy-processing=true").sources(BareConfiguration.class).run(); .sources(BareConfiguration.class).run();
then(this.context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("bar"); then(this.context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("bar");
} }
@Test @Test
public void systemPropertyOverrideFalse() { public void systemPropertyOverrideFalse() {
systemPropertyOverrideFalse("spring.config.use-legacy-processing=true");
}
@Test
public void systemPropertyOverrideFalseWithAppContext() {
systemPropertyOverrideFalse("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void systemPropertyOverrideFalse(String... properties) {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar"); PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
PropertySourceConfiguration.MAP.put("spring.cloud.config.overrideSystemProperties", "false"); PropertySourceConfiguration.MAP.put("spring.cloud.config.overrideSystemProperties", "false");
System.setProperty("bootstrap.foo", "system"); System.setProperty("bootstrap.foo", "system");
this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE) this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).properties(properties)
.properties("spring.config.use-legacy-processing=true").sources(BareConfiguration.class).run(); .sources(BareConfiguration.class).run();
then(this.context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("system"); then(this.context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("system");
} }
@Test @Test
public void systemPropertyOverrideWhenOverrideDisallowed() { public void systemPropertyOverrideWhenOverrideDisallowed() {
systemPropertyOverrideWhenOverrideDisallowed("spring.config.use-legacy-processing=true");
}
@Test
public void systemPropertyOverrideWhenOverrideDisallowedWithAppContext() {
systemPropertyOverrideWhenOverrideDisallowed("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void systemPropertyOverrideWhenOverrideDisallowed(String... properties) {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar"); PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
PropertySourceConfiguration.MAP.put("spring.cloud.config.overrideSystemProperties", "false"); PropertySourceConfiguration.MAP.put("spring.cloud.config.overrideSystemProperties", "false");
// If spring.cloud.config.allowOverride=false is in the remote property sources // If spring.cloud.config.allowOverride=false is in the remote property sources
@ -179,42 +258,71 @@ public class BootstrapConfigurationTests {
// their own remote property source. // their own remote property source.
PropertySourceConfiguration.MAP.put("spring.cloud.config.allowOverride", "false"); PropertySourceConfiguration.MAP.put("spring.cloud.config.allowOverride", "false");
System.setProperty("bootstrap.foo", "system"); System.setProperty("bootstrap.foo", "system");
this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE) this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).properties(properties)
.properties("spring.config.use-legacy-processing=true").sources(BareConfiguration.class).run(); .sources(BareConfiguration.class).run();
then(this.context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("bar"); then(this.context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("bar");
} }
@Test @Test
public void systemPropertyOverrideFalseWhenOverrideAllowed() { public void systemPropertyOverrideFalseWhenOverrideAllowed() {
systemPropertyOverrideFalseWhenOverrideAllowed("spring.config.use-legacy-processing=true");
}
@Test
public void systemPropertyOverrideFalseWhenOverrideAllowedWithAppContext() {
systemPropertyOverrideFalseWhenOverrideAllowed("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void systemPropertyOverrideFalseWhenOverrideAllowed(String... properties) {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar"); PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
PropertySourceConfiguration.MAP.put("spring.cloud.config.overrideSystemProperties", "false"); PropertySourceConfiguration.MAP.put("spring.cloud.config.overrideSystemProperties", "false");
PropertySourceConfiguration.MAP.put("spring.cloud.config.allowOverride", "true"); PropertySourceConfiguration.MAP.put("spring.cloud.config.allowOverride", "true");
System.setProperty("bootstrap.foo", "system"); System.setProperty("bootstrap.foo", "system");
this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE) this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).properties(properties)
.properties("spring.config.use-legacy-processing=true").sources(BareConfiguration.class).run(); .sources(BareConfiguration.class).run();
then(this.context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("system"); then(this.context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("system");
} }
@Test @Test
public void overrideAllWhenOverrideAllowed() { public void overrideAllWhenOverrideAllowed() {
overrideAllWhenOverrideAllowed("spring.config.use-legacy-processing=true");
}
@Test
public void overrideAllWhenOverrideAllowedWithAppContext() {
overrideAllWhenOverrideAllowed("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void overrideAllWhenOverrideAllowed(String... properties) {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar"); PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
PropertySourceConfiguration.MAP.put("spring.cloud.config.overrideNone", "true"); PropertySourceConfiguration.MAP.put("spring.cloud.config.overrideNone", "true");
PropertySourceConfiguration.MAP.put("spring.cloud.config.allowOverride", "true"); PropertySourceConfiguration.MAP.put("spring.cloud.config.allowOverride", "true");
ConfigurableEnvironment environment = new StandardEnvironment(); ConfigurableEnvironment environment = new StandardEnvironment();
environment.getPropertySources().addLast( environment.getPropertySources().addLast(
new MapPropertySource("last", Collections.<String, Object>singletonMap("bootstrap.foo", "splat"))); new MapPropertySource("last", Collections.<String, Object>singletonMap("bootstrap.foo", "splat")));
this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE) this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).properties(properties)
.properties("spring.config.use-legacy-processing=true").environment(environment) .environment(environment).sources(BareConfiguration.class).run();
.sources(BareConfiguration.class).run();
then(this.context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("splat"); then(this.context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("splat");
} }
@Test @Test
public void applicationNameInBootstrapAndMain() { public void applicationNameInBootstrapAndMain() {
applicationNameInBootstrapAndMain("spring.cloud.bootstrap.name:other",
"spring.config.use-legacy-processing=true", "spring.config.name:plain");
}
@Test
public void applicationNameInBootstrapAndMainWithAppContext() {
applicationNameInBootstrapAndMain("spring.cloud.bootstrap.name:other",
"spring.config.use-legacy-processing=true", "spring.config.name:plain",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void applicationNameInBootstrapAndMain(String... properties) {
System.setProperty("expected.name", "main"); System.setProperty("expected.name", "main");
this.context = new SpringApplicationBuilder() this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).properties(properties)
.web(WebApplicationType.NONE).properties("spring.cloud.bootstrap.name:other",
"spring.config.use-legacy-processing=true", "spring.config.name:plain")
.sources(BareConfiguration.class).run(); .sources(BareConfiguration.class).run();
then(this.context.getEnvironment().getProperty("spring.application.name")).isEqualTo("app"); then(this.context.getEnvironment().getProperty("spring.application.name")).isEqualTo("app");
// The parent is called "main" because spring.application.name is specified in // The parent is called "main" because spring.application.name is specified in
@ -228,10 +336,20 @@ public class BootstrapConfigurationTests {
@Test @Test
public void applicationNameNotInBootstrap() { public void applicationNameNotInBootstrap() {
applicationNameNotInBootstrap("spring.cloud.bootstrap.name:application",
"spring.config.use-legacy-processing=true", "spring.config.name:other");
}
@Test
public void applicationNameNotInBootstrapWithAppContext() {
applicationNameNotInBootstrap("spring.cloud.bootstrap.name:application",
"spring.config.use-legacy-processing=true", "spring.config.name:other",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void applicationNameNotInBootstrap(String... properties) {
System.setProperty("expected.name", "main"); System.setProperty("expected.name", "main");
this.context = new SpringApplicationBuilder() this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).properties(properties)
.web(WebApplicationType.NONE).properties("spring.cloud.bootstrap.name:application",
"spring.config.use-legacy-processing=true", "spring.config.name:other")
.sources(BareConfiguration.class).run(); .sources(BareConfiguration.class).run();
then(this.context.getEnvironment().getProperty("spring.application.name")).isEqualTo("main"); then(this.context.getEnvironment().getProperty("spring.application.name")).isEqualTo("main");
// The parent has no name because spring.application.name is not // The parent has no name because spring.application.name is not
@ -241,9 +359,18 @@ public class BootstrapConfigurationTests {
@Test @Test
public void applicationNameOnlyInBootstrap() { public void applicationNameOnlyInBootstrap() {
applicationNameOnlyInBootstrap("spring.cloud.bootstrap.name:other", "spring.config.use-legacy-processing=true");
}
@Test
public void applicationNameOnlyInBootstrapWithAppContext() {
applicationNameOnlyInBootstrap("spring.cloud.bootstrap.name:other", "spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void applicationNameOnlyInBootstrap(String... properties) {
System.setProperty("expected.name", "main"); System.setProperty("expected.name", "main");
this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE) this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).properties(properties)
.properties("spring.cloud.bootstrap.name:other", "spring.config.use-legacy-processing=true")
.sources(BareConfiguration.class).run(); .sources(BareConfiguration.class).run();
// The main context is called "main" because spring.application.name is specified // The main context is called "main" because spring.application.name is specified
// in other.properties (and not in the main config file) // in other.properties (and not in the main config file)
@ -256,10 +383,20 @@ public class BootstrapConfigurationTests {
@Test @Test
public void environmentEnrichedOnceWhenSharedWithChildContext() { public void environmentEnrichedOnceWhenSharedWithChildContext() {
environmentEnrichedOnceWhenSharedWithChildContext("spring.config.use-legacy-processing=true");
}
@Test
public void environmentEnrichedOnceWhenSharedWithChildContextWithAppContext() {
environmentEnrichedOnceWhenSharedWithChildContext("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void environmentEnrichedOnceWhenSharedWithChildContext(String... properties) {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar"); PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
this.context = new SpringApplicationBuilder().sources(BareConfiguration.class) this.context = new SpringApplicationBuilder().sources(BareConfiguration.class).properties(properties)
.properties("spring.config.use-legacy-processing=true").environment(new StandardEnvironment()) .environment(new StandardEnvironment()).child(BareConfiguration.class).web(WebApplicationType.NONE)
.child(BareConfiguration.class).web(WebApplicationType.NONE).run(); .run();
then(this.context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("bar"); then(this.context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("bar");
then(this.context.getParent().getEnvironment()).isEqualTo(this.context.getEnvironment()); then(this.context.getParent().getEnvironment()).isEqualTo(this.context.getEnvironment());
MutablePropertySources sources = this.context.getEnvironment().getPropertySources(); MutablePropertySources sources = this.context.getEnvironment().getPropertySources();
@ -271,11 +408,20 @@ public class BootstrapConfigurationTests {
@Test @Test
public void onlyOneBootstrapContext() { public void onlyOneBootstrapContext() {
onlyOneBootstrapContext("spring.config.use-legacy-processing=true");
}
@Test
public void onlyOneBootstrapContextWithAppContext() {
onlyOneBootstrapContext("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void onlyOneBootstrapContext(String... properties) {
TestHigherPriorityBootstrapConfiguration.count.set(0); TestHigherPriorityBootstrapConfiguration.count.set(0);
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar"); PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
this.context = new SpringApplicationBuilder().sources(BareConfiguration.class) this.context = new SpringApplicationBuilder().sources(BareConfiguration.class).properties(properties)
.properties("spring.config.use-legacy-processing=true").child(BareConfiguration.class) .child(BareConfiguration.class).web(WebApplicationType.NONE).run();
.web(WebApplicationType.NONE).run();
then(TestHigherPriorityBootstrapConfiguration.count.get()).isEqualTo(1); then(TestHigherPriorityBootstrapConfiguration.count.get()).isEqualTo(1);
then(this.context.getParent()).isNotNull(); then(this.context.getParent()).isNotNull();
then(this.context.getParent().getParent().getId()).isEqualTo("bootstrap"); then(this.context.getParent().getParent().getId()).isEqualTo("bootstrap");
@ -285,9 +431,18 @@ public class BootstrapConfigurationTests {
@Test @Test
public void listOverride() { public void listOverride() {
this.context = new SpringApplicationBuilder().sources(BareConfiguration.class) listOverride("spring.config.use-legacy-processing=true");
.properties("spring.config.use-legacy-processing=true").child(BareConfiguration.class) }
.web(WebApplicationType.NONE).run();
@Test
public void listOverrideWithAppContext() {
listOverride("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void listOverride(String... properties) {
this.context = new SpringApplicationBuilder().sources(BareConfiguration.class).properties(properties)
.child(BareConfiguration.class).web(WebApplicationType.NONE).run();
ListProperties listProperties = new ListProperties(); ListProperties listProperties = new ListProperties();
Binder.get(this.context.getEnvironment()).bind("list", Bindable.ofInstance(listProperties)); Binder.get(this.context.getEnvironment()).bind("list", Bindable.ofInstance(listProperties));
then(listProperties.getFoo().size()).isEqualTo(1); then(listProperties.getFoo().size()).isEqualTo(1);
@ -296,10 +451,20 @@ public class BootstrapConfigurationTests {
@Test @Test
public void bootstrapContextSharedBySiblings() { public void bootstrapContextSharedBySiblings() {
bootstrapContextSharedBySiblings("spring.config.use-legacy-processing=true");
}
@Test
public void bootstrapContextSharedBySiblingsWithAppContext() {
bootstrapContextSharedBySiblings("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void bootstrapContextSharedBySiblings(String... properties) {
TestHigherPriorityBootstrapConfiguration.count.set(0); TestHigherPriorityBootstrapConfiguration.count.set(0);
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar"); PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
SpringApplicationBuilder builder = new SpringApplicationBuilder() SpringApplicationBuilder builder = new SpringApplicationBuilder().properties(properties)
.properties("spring.config.use-legacy-processing=true").sources(BareConfiguration.class); .sources(BareConfiguration.class);
this.sibling = builder.child(BareConfiguration.class).properties("spring.application.name=sibling") this.sibling = builder.child(BareConfiguration.class).properties("spring.application.name=sibling")
.web(WebApplicationType.NONE).run(); .web(WebApplicationType.NONE).run();
this.context = builder.child(BareConfiguration.class).properties("spring.application.name=context") this.context = builder.child(BareConfiguration.class).properties("spring.application.name=context")
@ -319,10 +484,19 @@ public class BootstrapConfigurationTests {
@Test @Test
public void environmentEnrichedInParentContext() { public void environmentEnrichedInParentContext() {
environmentEnrichedInParentContext("spring.config.use-legacy-processing=true");
}
@Test
public void environmentEnrichedInParentContextWithAppContext() {
environmentEnrichedInParentContext("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void environmentEnrichedInParentContext(String... properties) {
PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar"); PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar");
this.context = new SpringApplicationBuilder().sources(BareConfiguration.class) this.context = new SpringApplicationBuilder().sources(BareConfiguration.class).properties(properties)
.properties("spring.config.use-legacy-processing=true").child(BareConfiguration.class) .child(BareConfiguration.class).web(WebApplicationType.NONE).run();
.web(WebApplicationType.NONE).run();
then(this.context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("bar"); then(this.context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("bar");
then(this.context.getParent().getEnvironment()).isNotSameAs(this.context.getEnvironment()); then(this.context.getParent().getEnvironment()).isNotSameAs(this.context.getEnvironment());
then(this.context.getEnvironment().getPropertySources() then(this.context.getEnvironment().getPropertySources()
@ -365,27 +539,118 @@ public class BootstrapConfigurationTests {
@Test @Test
public void includeProfileFromBootstrapPropertySource() { public void includeProfileFromBootstrapPropertySource() {
includeProfileFromBootstrapPropertySource("spring.config.use-legacy-processing=true");
}
@Test
public void includeProfileFromBootstrapPropertySourceWithAppContext() {
includeProfileFromBootstrapPropertySource("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void includeProfileFromBootstrapPropertySource(String... properties) {
PropertySourceConfiguration.MAP.put("spring.profiles.include", "bar,baz"); PropertySourceConfiguration.MAP.put("spring.profiles.include", "bar,baz");
this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE) this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).properties(properties)
.properties("spring.config.use-legacy-processing=true").profiles("foo").sources(BareConfiguration.class) .profiles("foo").sources(BareConfiguration.class).run();
.run();
then(this.context.getEnvironment().acceptsProfiles("baz")).isTrue(); then(this.context.getEnvironment().acceptsProfiles("baz")).isTrue();
then(this.context.getEnvironment().acceptsProfiles("bar")).isTrue(); then(this.context.getEnvironment().acceptsProfiles("bar")).isTrue();
} }
@Test
public void activeProfileFromBootstrapPropertySource() {
activeProfileFromBootstrapPropertySource("spring.config.use-legacy-processing=true");
}
@Test
public void activeProfileFromBootstrapPropertySourceWithAppContext() {
activeProfileFromBootstrapPropertySource("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
then(this.context.getEnvironment().getActiveProfiles()).doesNotContain("after");
}
private void activeProfileFromBootstrapPropertySource(String... properties) {
PropertySourceConfiguration.MAP.put("spring.profiles.active", "bar,baz");
this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).properties(properties)
.profiles("foo").sources(BareConfiguration.class).run();
then(this.context.getEnvironment().acceptsProfiles("baz", "bar", "foo")).isTrue();
then(this.context.getEnvironment().getActiveProfiles()).contains("baz", "bar", "foo");
}
@Test
public void activeAndIncludeProfileFromBootstrapPropertySource() {
activeAndIncludeProfileFromBootstrapPropertySource("spring.config.use-legacy-processing=true");
}
@Test
public void activeAndIncludeProfileFromBootstrapPropertySourceWithAppContext() {
activeAndIncludeProfileFromBootstrapPropertySource("spring.config.use-legacy-processing=true",
"spring.cloud.config.initialize-on-context-refresh=true");
}
private void activeAndIncludeProfileFromBootstrapPropertySource(String... properties) {
PropertySourceConfiguration.MAP.put("spring.profiles.active", "bar,baz");
PropertySourceConfiguration.MAP.put("spring.profiles.include", "bar,baz,hello");
this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).properties(properties)
.profiles("foo").sources(BareConfiguration.class).run();
then(this.context.getEnvironment().acceptsProfiles("baz", "bar", "hello", "foo")).isTrue();
then(this.context.getEnvironment().getActiveProfiles()).contains("baz", "bar", "foo", "hello");
}
@Test
public void activeAndIncludeProfileFromBootstrapPropertySourceWithReplacement() {
activeAndIncludeProfileFromBootstrapPropertySourceWithReplacement("spring.config.use-legacy-processing=true",
"barreplacement=bar");
}
@Test
public void activeAndIncludeProfileFromBootstrapPropertySourceWithReplacementWithAppContext() {
activeAndIncludeProfileFromBootstrapPropertySourceWithReplacement("spring.config.use-legacy-processing=true",
"barreplacement=bar", "spring.cloud.config.initialize-on-context-refresh=true");
}
private void activeAndIncludeProfileFromBootstrapPropertySourceWithReplacement(String... properties) {
PropertySourceConfiguration.MAP.put("spring.profiles.active", "${barreplacement},baz");
PropertySourceConfiguration.MAP.put("spring.profiles.include", "${barreplacement},baz,hello");
this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).properties(properties)
.profiles("foo").sources(BareConfiguration.class).run();
then(this.context.getEnvironment().acceptsProfiles("baz", "bar", "hello", "foo")).isTrue();
then(this.context.getEnvironment().getActiveProfiles()).contains("baz", "bar", "foo", "hello");
}
@Test @Test
public void includeProfileFromBootstrapProperties() { public void includeProfileFromBootstrapProperties() {
includeProfileFromBootstrapProperties("spring.config.use-legacy-processing=true",
"spring.cloud.bootstrap.name=local");
}
@Test
public void includeProfileFromBootstrapPropertiesWithAppContext() {
includeProfileFromBootstrapProperties("spring.config.use-legacy-processing=true",
"spring.cloud.bootstrap.name=local", "spring.cloud.config.initialize-on-context-refresh=true");
}
private void includeProfileFromBootstrapProperties(String... properties) {
this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(BareConfiguration.class) this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(BareConfiguration.class)
.properties("spring.config.use-legacy-processing=true", "spring.cloud.bootstrap.name=local").run(); .properties(properties).run();
then(this.context.getEnvironment().acceptsProfiles("local")).isTrue(); then(this.context.getEnvironment().acceptsProfiles("local")).isTrue();
then(this.context.getEnvironment().getProperty("added")).isEqualTo("Hello added!"); then(this.context.getEnvironment().getProperty("added")).isEqualTo("Hello added!");
} }
@Test @Test
public void nonEnumerablePropertySourceWorks() { public void nonEnumerablePropertySourceWorks() {
nonEnumerablePropertySourceWorks("spring.config.use-legacy-processing=true",
"spring.cloud.bootstrap.name=nonenumerable");
}
@Test
public void nonEnumerablePropertySourceWorksWithAppContext() {
nonEnumerablePropertySourceWorks("spring.config.use-legacy-processing=true",
"spring.cloud.bootstrap.name=nonenumerable", "spring.cloud.config.initialize-on-context-refresh=true");
}
private void nonEnumerablePropertySourceWorks(String... properties) {
this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(BareConfiguration.class) this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(BareConfiguration.class)
.properties("spring.config.use-legacy-processing=true", "spring.cloud.bootstrap.name=nonenumerable") .properties(properties).run();
.run();
then(this.context.getEnvironment().getProperty("foo")).isEqualTo("bar"); then(this.context.getEnvironment().getProperty("foo")).isEqualTo("bar");
} }
@ -425,12 +690,24 @@ public class BootstrapConfigurationTests {
@Override @Override
public PropertySource<?> locate(Environment environment) { public PropertySource<?> locate(Environment environment) {
if (environment instanceof ConfigurableEnvironment) {
if (!((ConfigurableEnvironment) environment).getPropertySources()
.contains(BootstrapApplicationListener.BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
if (MAP.containsKey(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME)) {
// This additional profile, after, should not be added when
// initialize-on-context-refresh=true
MAP.put(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME,
MAP.get(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME) + ",after");
}
}
}
if (this.name != null) { if (this.name != null) {
then(this.name).isEqualTo(environment.getProperty("spring.application.name")); then(this.name).isEqualTo(environment.getProperty("spring.application.name"));
} }
if (this.fail) { if (this.fail) {
throw new RuntimeException("Planned"); throw new RuntimeException("Planned");
} }
return new MapPropertySource("testBootstrap", MAP); return new MapPropertySource("testBootstrap", MAP);
} }

Loading…
Cancel
Save