Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
package org.springframework.cloud.bootstrap.config;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
Expand All @@ -45,13 +47,17 @@
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;

import static org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME;
import static org.springframework.core.env.StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME;

/**
* @author Dave Syer
*
Expand Down Expand Up @@ -87,27 +93,31 @@ public void setPropertySourceLocators(

@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
CompositePropertySource composite = new CompositePropertySource(
BOOTSTRAP_PROPERTY_SOURCE_NAME);
List<PropertySource<?>> composite = new ArrayList<>();
AnnotationAwareOrderComparator.sort(this.propertySourceLocators);
boolean empty = true;
ConfigurableEnvironment environment = applicationContext.getEnvironment();
for (PropertySourceLocator locator : this.propertySourceLocators) {
PropertySource<?> source = null;
source = locator.locate(environment);
Collection<PropertySource<?>> source = locator.locateCollection(environment);
if (source == null) {
continue;
}
logger.info("Located property source: " + source);
composite.addPropertySource(source);
List sourceList = new ArrayList<>();
for (PropertySource p : source) {
sourceList.add(new BootstrapPropertySource(p));
}
logger.info("Located property source: " + sourceList);
composite.addAll(sourceList);
empty = false;
}
if (!empty) {
MutablePropertySources propertySources = environment.getPropertySources();
String logConfig = environment.resolvePlaceholders("${logging.config:}");
LogFile logFile = LogFile.get(environment);
if (propertySources.contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
propertySources.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME);
for (PropertySource p : environment.getPropertySources()) {
if (p.getName().startsWith(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
propertySources.remove(p.getName());
}
}
insertPropertySources(propertySources, composite);
reinitializeLoggingSystem(environment, logConfig, logFile);
Expand Down Expand Up @@ -154,36 +164,49 @@ private void setLogLevels(ConfigurableApplicationContext applicationContext,
}

private void insertPropertySources(MutablePropertySources propertySources,
CompositePropertySource composite) {
List<PropertySource<?>> composite) {
MutablePropertySources incoming = new MutablePropertySources();
incoming.addFirst(composite);
List<PropertySource<?>> reversedComposite = new ArrayList(composite);
// Reverse the list so that when we call addFirst below we are maintaining the
// same order of PropertySournces
// Wherever we call addLast we can use the order in the List since the first item
// will end up before the rest
Collections.reverse(reversedComposite);
for (PropertySource p : reversedComposite) {
incoming.addFirst(p);
}
PropertySourceBootstrapProperties remoteProperties = new PropertySourceBootstrapProperties();
Binder.get(environment(incoming)).bind("spring.cloud.config",
Bindable.ofInstance(remoteProperties));
if (!remoteProperties.isAllowOverride() || (!remoteProperties.isOverrideNone()
&& remoteProperties.isOverrideSystemProperties())) {
propertySources.addFirst(composite);
for (PropertySource p : reversedComposite) {
propertySources.addFirst(p);
}
return;
}
if (remoteProperties.isOverrideNone()) {
propertySources.addLast(composite);
for (PropertySource p : composite) {
propertySources.addLast(p);
}
return;
}
if (propertySources
.contains(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME)) {
if (propertySources.contains(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME)) {
if (!remoteProperties.isOverrideSystemProperties()) {
propertySources.addAfter(
StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
composite);
for (PropertySource p : composite) {
propertySources.addAfter(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, p);
}
}
else {
propertySources.addBefore(
StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
composite);
for (PropertySource p : reversedComposite) {
propertySources.addBefore(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, p);
}
}
}
else {
propertySources.addLast(composite);
for (PropertySource p : composite) {
propertySources.addLast(p);
}
}
}

Expand Down Expand Up @@ -241,3 +264,32 @@ private String[] getProfilesForValue(Object property) {
}

}

class BootstrapPropertySource<T> extends EnumerablePropertySource<T> {

private PropertySource<T> p;

BootstrapPropertySource(PropertySource<T> p) {
super(BOOTSTRAP_PROPERTY_SOURCE_NAME + "-" + p.getName(), p.getSource());
this.p = p;
}

@Override
public Object getProperty(String name) {
return p.getProperty(name);
}

@Override
public String[] getPropertyNames() {
Set<String> names = new LinkedHashSet<>();
if (!(this.p instanceof EnumerablePropertySource)) {
throw new IllegalStateException(
"Failed to enumerate property names due to non-enumerable property source: "
+ p);
}
names.addAll(Arrays.asList(((EnumerablePropertySource<?>) p).getPropertyNames()));

return StringUtils.toStringArray(names);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@

package org.springframework.cloud.bootstrap.config;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;

Expand All @@ -36,4 +41,14 @@ public interface PropertySourceLocator {
*/
PropertySource<?> locate(Environment environment);

default Collection<PropertySource<?>> locateCollection(Environment environment) {
PropertySource propertySource = locate(environment);
if (CompositePropertySource.class.isInstance(propertySource)) {
return ((CompositePropertySource) propertySource).getPropertySources();
}
else {
return (List) Arrays.asList(propertySource);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.junit.After;
Expand All @@ -29,10 +30,13 @@
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.cloud.bootstrap.TestHigherPriorityBootstrapConfiguration;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
Expand Down Expand Up @@ -63,6 +67,8 @@ public void close() {
// Used to test system properties override
System.clearProperty("bootstrap.foo");
PropertySourceConfiguration.MAP.clear();
CompositePropertySourceConfiguration.MAP1.clear();
CompositePropertySourceConfiguration.MAP2.clear();
if (this.context != null) {
this.context.close();
}
Expand All @@ -82,8 +88,8 @@ public void pickupExternalBootstrapProperties() {
then(this.context.getEnvironment().getProperty("info.name"))
.isEqualTo("externalPropertiesInfoName");
then(this.context.getEnvironment().getPropertySources().contains(
PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME))
.isTrue();
PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME
+ "-testBootstrap")).isTrue();
}

@Test
Expand All @@ -101,8 +107,8 @@ public void initialize(
})
.run();
then(this.context.getEnvironment().getPropertySources().contains(
PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME))
.isTrue();
PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME
+ "-testBootstrap")).isTrue();
}

/**
Expand All @@ -122,8 +128,8 @@ public void picksUpAdditionalPropertySource() {
.sources(BareConfiguration.class).run();
then(this.context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("bar");
then(this.context.getEnvironment().getPropertySources().contains(
PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME))
.isTrue();
PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME
+ "-testBootstrap")).isTrue();
}

@Test
Expand Down Expand Up @@ -262,7 +268,8 @@ public void environmentEnrichedOnceWhenSharedWithChildContext() {
MutablePropertySources sources = this.context.getEnvironment()
.getPropertySources();
PropertySource<?> bootstrap = sources
.get(PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME);
.get(PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME
+ "-testBootstrap");
then(bootstrap).isNotNull();
then(sources.precedenceOf(bootstrap)).isEqualTo(0);
}
Expand All @@ -280,6 +287,17 @@ public void onlyOneBootstrapContext() {
then(this.context.getEnvironment().getProperty("custom.foo")).isEqualTo("bar");
}

@Test
public void listOverride() {
this.context = new SpringApplicationBuilder().sources(BareConfiguration.class)
.child(BareConfiguration.class).web(WebApplicationType.NONE).run();
ListProperties listProperties = new ListProperties();
Binder.get(this.context.getEnvironment()).bind("list",
Bindable.ofInstance(listProperties));
then(listProperties.getFoo().size()).isEqualTo(1);
then(listProperties.getFoo().get(0)).isEqualTo("hello world");
}

@Test
public void bootstrapContextSharedBySiblings() {
TestHigherPriorityBootstrapConfiguration.count.set(0);
Expand Down Expand Up @@ -318,12 +336,12 @@ public void environmentEnrichedInParentContext() {
then(this.context.getParent().getEnvironment())
.isNotSameAs(this.context.getEnvironment());
then(this.context.getEnvironment().getPropertySources().contains(
PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME))
.isTrue();
PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME
+ "-testBootstrap")).isTrue();
then(((ConfigurableEnvironment) this.context.getParent().getEnvironment())
.getPropertySources().contains(
PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME))
.isTrue();
PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME
+ "-testBootstrap")).isTrue();
}

@Test
Expand All @@ -347,8 +365,8 @@ public void differentProfileInChild() {
.isTrue();
then(((ConfigurableEnvironment) this.context.getParent().getEnvironment())
.getPropertySources().contains(
PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME))
.isTrue();
PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME
+ "-testBootstrap")).isTrue();
then(this.context.getEnvironment().getProperty("bootstrap.foo")).isEqualTo("bar");
// The "bootstrap" property source is not shared now, but it has the same
// properties in it because they are pulled from the PropertySourceConfiguration
Expand Down Expand Up @@ -427,4 +445,74 @@ public void setFail(boolean fail) {

}

@Configuration
@ConfigurationProperties("compositeexpected")
// This is added to bootstrap context as a source in bootstrap.properties
protected static class CompositePropertySourceConfiguration
implements PropertySourceLocator {

public static Map<String, Object> MAP1 = new HashMap<String, Object>();

public static Map<String, Object> MAP2 = new HashMap<String, Object>();

public CompositePropertySourceConfiguration() {
MAP1.put("list.foo[0]", "hello");
MAP1.put("list.food[1]", "world");
MAP2.put("list.foo[0]", "hello world");
}

private String name;

private boolean fail = false;

@Override
public PropertySource<?> locate(Environment environment) {
if (this.name != null) {
then(this.name)
.isEqualTo(environment.getProperty("spring.application.name"));
}
if (this.fail) {
throw new RuntimeException("Planned");
}
CompositePropertySource compositePropertySource = new CompositePropertySource(
"listTestBootstrap");
compositePropertySource.addFirstPropertySource(
new MapPropertySource("testBootstrap1", MAP1));
compositePropertySource.addFirstPropertySource(
new MapPropertySource("testBootstrap2", MAP2));
return compositePropertySource;
}

public String getName() {
return this.name;
}

public void setName(String name) {
this.name = name;
}

public boolean isFail() {
return this.fail;
}

public void setFail(boolean fail) {
this.fail = fail;
}

}

protected static class ListProperties {

private List<String> foo;

public List<String> getFoo() {
return foo;
}

public void setFoo(List<String> foo) {
this.foo = foo;
}

}

}
Loading