Use additional properties instead of default args
SpringApplication (and the builder) now do not accept default command line args because the override semantics were wrong - you need to be able to override them with everything, including system properties and external properties (per profile). Also implements new semantics for profiles - you can add additional profiles in the Java API and they will not be squashed by command line or system properties entries for spring.profiles.active. [Fixes #58989906] [bs-336] DefaultArgs -> DefaultProperties
This commit is contained in:
@@ -19,8 +19,13 @@ package org.springframework.boot;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -43,6 +48,8 @@ import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.env.CommandLinePropertySource;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.env.SimpleCommandLinePropertySource;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
@@ -162,7 +169,9 @@ public class SpringApplication {
|
||||
|
||||
private List<ApplicationContextInitializer<?>> initializers;
|
||||
|
||||
private String[] defaultArgs;
|
||||
private Map<String, Object> defaultProperties;
|
||||
|
||||
private Set<String> profiles = new HashSet<String>();
|
||||
|
||||
/**
|
||||
* Crate a new {@link SpringApplication} instance. The application context will load
|
||||
@@ -255,6 +264,9 @@ public class SpringApplication {
|
||||
// Create and configure the environment
|
||||
ConfigurableEnvironment environment = getOrCreateEnvironment();
|
||||
addPropertySources(environment, args);
|
||||
for (String profile : this.profiles) {
|
||||
environment.addActiveProfile(profile);
|
||||
}
|
||||
|
||||
// Call all remaining initializers
|
||||
callEnvironmentAwareSpringApplicationInitializers(args, environment);
|
||||
@@ -321,12 +333,11 @@ public class SpringApplication {
|
||||
* @param args run arguments
|
||||
*/
|
||||
protected void addPropertySources(ConfigurableEnvironment environment, String[] args) {
|
||||
if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
|
||||
environment.getPropertySources().addLast(
|
||||
new MapPropertySource("defaultProperties", this.defaultProperties));
|
||||
}
|
||||
if (this.addCommandLineProperties) {
|
||||
if (this.defaultArgs != null) {
|
||||
environment.getPropertySources().addFirst(
|
||||
new SimpleCommandLinePropertySource("defaultCommandLineArgs",
|
||||
this.defaultArgs));
|
||||
}
|
||||
environment.getPropertySources().addFirst(
|
||||
new SimpleCommandLinePropertySource(args));
|
||||
}
|
||||
@@ -557,13 +568,34 @@ public class SpringApplication {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default arguments which will be used in addition to those specified to the
|
||||
* {@code run} methods. Default arguments can always be overridden by user defined
|
||||
* arguments..
|
||||
* @param defaultArgs the default args to set
|
||||
* Set default environment properties which will be used in addition to those in the
|
||||
* existing {@link Environment}.
|
||||
* @param defaultProperties the additional properties to set
|
||||
*/
|
||||
public void setDefaultArgs(String... defaultArgs) {
|
||||
this.defaultArgs = defaultArgs;
|
||||
public void setDefaultProperties(Map<String, Object> defaultProperties) {
|
||||
this.defaultProperties = defaultProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient alternative to {@link #setDefaultProperties(Map)}.
|
||||
*
|
||||
* @param defaultProperties some {@link Properties}
|
||||
*/
|
||||
public void setDefaultProperties(Properties defaultProperties) {
|
||||
this.defaultProperties = new HashMap<String, Object>();
|
||||
for (Object key : Collections.list(defaultProperties.propertyNames())) {
|
||||
this.defaultProperties.put((String) key, defaultProperties.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set additional profile values to use (on top of those set in system or command line
|
||||
* properties).
|
||||
*
|
||||
* @param profiles the additional profiles to set
|
||||
*/
|
||||
public void setAdditionalProfiles(Collection<String> profiles) {
|
||||
this.profiles = new LinkedHashSet<String>(profiles);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,7 +16,11 @@
|
||||
package org.springframework.boot.builder;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@@ -29,7 +33,6 @@ import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Builder for {@link SpringApplication} and {@link ApplicationContext} instances with
|
||||
@@ -62,8 +65,9 @@ public class SpringApplicationBuilder {
|
||||
private SpringApplicationBuilder parent;
|
||||
private AtomicBoolean running = new AtomicBoolean(false);
|
||||
private Set<Object> sources = new LinkedHashSet<Object>();
|
||||
private Set<String> defaultArgs = new LinkedHashSet<String>();
|
||||
private Map<String, Object> defaultProperties = new LinkedHashMap<String, Object>();
|
||||
private ConfigurableEnvironment environment;
|
||||
private Set<String> additionalProfiles = new LinkedHashSet<String>();
|
||||
|
||||
public SpringApplicationBuilder(Object... sources) {
|
||||
this.application = new SpringApplication(sources);
|
||||
@@ -134,8 +138,8 @@ public class SpringApplicationBuilder {
|
||||
child.sources(sources);
|
||||
|
||||
// Copy environment stuff from parent to child
|
||||
child.defaultArgs(this.defaultArgs.toArray(new String[this.defaultArgs.size()]))
|
||||
.environment(this.environment);
|
||||
child.properties(this.defaultProperties).environment(this.environment)
|
||||
.additionalProfiles(this.additionalProfiles);
|
||||
child.parent = this;
|
||||
|
||||
// It's not possible if embedded containers are enabled to support web contexts as
|
||||
@@ -163,7 +167,7 @@ public class SpringApplicationBuilder {
|
||||
public SpringApplicationBuilder parent(Object... sources) {
|
||||
if (this.parent == null) {
|
||||
this.parent = new SpringApplicationBuilder(sources).web(false)
|
||||
.defaultArgs(this.defaultArgs).environment(this.environment);
|
||||
.properties(this.defaultProperties).environment(this.environment);
|
||||
}
|
||||
else {
|
||||
this.parent.sources(sources);
|
||||
@@ -315,39 +319,66 @@ public class SpringApplicationBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Default command line arguments (overridden by explicit arguments at runtime in
|
||||
* {@link #run(String...)}).
|
||||
* Default properties for the environment in the form <code>key=value</code> or
|
||||
* <code>key:value</code>.
|
||||
*
|
||||
* @param defaultArgs the args to set.
|
||||
* @param defaultProperties the properties to set.
|
||||
* @return the current builder
|
||||
*/
|
||||
public SpringApplicationBuilder defaultArgs(String... defaultArgs) {
|
||||
this.defaultArgs.addAll(Arrays.asList(defaultArgs));
|
||||
this.application.setDefaultArgs(this.defaultArgs
|
||||
.toArray(new String[this.defaultArgs.size()]));
|
||||
public SpringApplicationBuilder properties(String... defaultProperties) {
|
||||
this.defaultProperties.putAll(getMapFromKeyValuePairs(defaultProperties));
|
||||
this.application.setDefaultProperties(this.defaultProperties);
|
||||
if (this.parent != null) {
|
||||
this.parent.defaultArgs(defaultArgs);
|
||||
this.parent.properties(defaultProperties);
|
||||
this.parent.environment(this.environment);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private SpringApplicationBuilder defaultArgs(Set<String> defaultArgs) {
|
||||
this.defaultArgs = defaultArgs;
|
||||
private Map<String, Object> getMapFromKeyValuePairs(String[] args) {
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
for (String pair : args) {
|
||||
int index = pair.indexOf(":");
|
||||
if (index <= 0) {
|
||||
index = pair.indexOf("=");
|
||||
}
|
||||
String key = pair.substring(0, index > 0 ? index : pair.length());
|
||||
String value = index > 0 ? pair.substring(index + 1) : "";
|
||||
map.put(key, value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default properties for the environment. Multiple calls to this method are
|
||||
* cumulative.
|
||||
*
|
||||
* @param defaults
|
||||
* @return the current builder
|
||||
*
|
||||
* @see SpringApplicationBuilder#properties(String...)
|
||||
*/
|
||||
public SpringApplicationBuilder properties(Map<String, Object> defaults) {
|
||||
this.defaultProperties.putAll(defaults);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the active Spring profiles for this app (and its parent and children).
|
||||
* Synonymous with {@link #defaultArgs(String...)
|
||||
* defaultArgs("--spring.profiles.active=[profiles]")}
|
||||
* Add to the active Spring profiles for this app (and its parent and children).
|
||||
*
|
||||
* @param profiles the profiles to set.
|
||||
* @param profiles the profiles to add.
|
||||
* @return the current builder
|
||||
*/
|
||||
public SpringApplicationBuilder profiles(String... profiles) {
|
||||
defaultArgs("--spring.profiles.active="
|
||||
+ StringUtils.arrayToCommaDelimitedString(profiles));
|
||||
this.additionalProfiles.addAll(Arrays.asList(profiles));
|
||||
this.application.setAdditionalProfiles(this.additionalProfiles);
|
||||
return this;
|
||||
}
|
||||
|
||||
private SpringApplicationBuilder additionalProfiles(
|
||||
Collection<String> additionalProfiles) {
|
||||
this.additionalProfiles = new LinkedHashSet<String>(additionalProfiles);
|
||||
this.application.setAdditionalProfiles(additionalProfiles);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -125,6 +125,8 @@ public class ConfigFileApplicationContextInitializer implements
|
||||
|
||||
List<String> candidates = getCandidateLocations();
|
||||
Collections.reverse(candidates);
|
||||
PropertySource<?> removed = environment.getPropertySources().remove(
|
||||
"defaultProperties");
|
||||
|
||||
List<PropertySource<?>> sources = new ArrayList<PropertySource<?>>();
|
||||
// Initial load allows profiles to be activated
|
||||
@@ -150,6 +152,10 @@ public class ConfigFileApplicationContextInitializer implements
|
||||
for (PropertySource<?> source : sources) {
|
||||
environment.getPropertySources().addLast(source);
|
||||
}
|
||||
|
||||
if (removed != null) {
|
||||
environment.getPropertySources().addLast(removed);
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getCandidateLocations() {
|
||||
|
||||
@@ -49,6 +49,7 @@ import org.springframework.core.env.StandardEnvironment;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
@@ -301,7 +302,8 @@ public class SpringApplicationTests {
|
||||
@Test
|
||||
public void defaultCommandLineArgs() throws Exception {
|
||||
SpringApplication application = new SpringApplication(ExampleConfig.class);
|
||||
application.setDefaultArgs("--baz", "--bar=spam", "bucket");
|
||||
application.setDefaultProperties(StringUtils.splitArrayElementsIntoProperties(
|
||||
new String[] { "baz=", "bar=spam" }, "="));
|
||||
application.setWebEnvironment(false);
|
||||
this.context = application.run("--bar=foo", "bucket", "crap");
|
||||
assertThat(this.context, instanceOf(AnnotationConfigApplicationContext.class));
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.boot.builder;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
@@ -48,14 +47,15 @@ public class SpringApplicationBuilderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void profileAndDefaultArgs() throws Exception {
|
||||
public void profileAndProperties() throws Exception {
|
||||
SpringApplicationBuilder application = new SpringApplicationBuilder()
|
||||
.sources(ExampleConfig.class)
|
||||
.contextClass(StaticApplicationContext.class).profiles("foo")
|
||||
.defaultArgs("--foo=bar");
|
||||
.properties("foo=bar");
|
||||
this.context = application.run();
|
||||
assertThat(this.context, is(instanceOf(StaticApplicationContext.class)));
|
||||
assertThat(this.context.getEnvironment().getProperty("foo"), is(equalTo("bar")));
|
||||
assertThat(this.context.getEnvironment().getProperty("foo"),
|
||||
is(equalTo("bucket")));
|
||||
assertThat(this.context.getEnvironment().acceptsProfiles("foo"), is(true));
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ public class SpringApplicationBuilderTests {
|
||||
@Test
|
||||
public void parentFirstCreationWithProfileAndDefaultArgs() throws Exception {
|
||||
SpringApplicationBuilder application = new SpringApplicationBuilder(
|
||||
ExampleConfig.class).profiles("node").defaultArgs("--transport=redis")
|
||||
ExampleConfig.class).profiles("node").properties("transport=redis")
|
||||
.child(ChildConfig.class).web(false);
|
||||
this.context = application.run();
|
||||
assertThat(this.context.getEnvironment().acceptsProfiles("node"), is(true));
|
||||
|
||||
@@ -18,8 +18,10 @@ package org.springframework.boot.test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
@@ -34,7 +36,6 @@ import org.springframework.test.context.support.AbstractContextLoader;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.context.web.WebMergedContextConfiguration;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.context.support.GenericWebApplicationContext;
|
||||
|
||||
/**
|
||||
@@ -63,16 +64,15 @@ public class SpringApplicationContextLoader extends AbstractContextLoader {
|
||||
SpringApplication application = new SpringApplication();
|
||||
application.setSources(sources);
|
||||
|
||||
Set<String> args = new LinkedHashSet<String>();
|
||||
Map<String, Object> args = new LinkedHashMap<String, Object>();
|
||||
if (!ObjectUtils.isEmpty(mergedConfig.getActiveProfiles())) {
|
||||
args.add("--spring.profiles.active="
|
||||
+ StringUtils.arrayToCommaDelimitedString(mergedConfig
|
||||
.getActiveProfiles()));
|
||||
application.setAdditionalProfiles(Arrays.asList(mergedConfig
|
||||
.getActiveProfiles()));
|
||||
}
|
||||
// Not running an embedded server, just setting up web context
|
||||
args.add("--server.port=0");
|
||||
args.add("--management.port=0");
|
||||
application.setDefaultArgs(args.toArray(new String[args.size()]));
|
||||
args.put("server.port", "0");
|
||||
args.put("management.port", "0");
|
||||
application.setDefaultProperties(args);
|
||||
List<ApplicationContextInitializer<?>> initializers = new ArrayList<ApplicationContextInitializer<?>>(
|
||||
application.getInitializers());
|
||||
for (Class<? extends ApplicationContextInitializer<?>> type : mergedConfig
|
||||
|
||||
Reference in New Issue
Block a user