Polish "Add support for environment variables"

Closes gh-12800
pull/12955/merge
Stephane Nicoll 7 years ago
parent 95f7e3ca37
commit 40b7e02793

@ -2771,14 +2771,6 @@ See {spring-boot-maven-plugin-site}/examples/run-debug.html[this example] for mo
details.
[[howto-set-env-maven-run]]
=== Run Spring Boot Application with Environment variables Started with Maven
To set up the environment variables to a Spring Boot application that was started with Maven, you
can use the `environmentVariables` property of the {spring-boot-maven-plugin-site}[maven plugin].
See {spring-boot-maven-plugin-site}/examples/run-with-env.html[this example] for more
details.
[[howto-build-an-executable-archive-with-ant]]
=== Build an Executable Archive from Ant without Using `spring-boot-antlib`

@ -69,12 +69,8 @@ public class RunProcess {
return run(waitForProcess, Arrays.asList(args), Collections.emptyMap());
}
public int run(boolean waitForProcess, String[] args, Map<String, String> environmentVariables) throws IOException {
return run(waitForProcess, Arrays.asList(args), environmentVariables);
}
protected int run(boolean waitForProcess, Collection<String> args, Map<String, String> environmentVariables)
throws IOException {
public int run(boolean waitForProcess, Collection<String> args,
Map<String, String> environmentVariables) throws IOException {
ProcessBuilder builder = new ProcessBuilder(this.command);
builder.directory(this.workingDirectory);
builder.command().addAll(args);

@ -18,7 +18,6 @@ package org.test;
public class SampleApplication {
public static void main(String[] args) {
assertEnvValue("ENV1", "5000");
assertEnvValue("ENV2", "Some Text");
@ -26,14 +25,13 @@ public class SampleApplication {
assertEnvValue("ENV4", "");
System.out.println("I haz been run");
}
static void assertEnvValue(String envKey, String expectedValue) {
private static void assertEnvValue(String envKey, String expectedValue) {
String actual = System.getenv(envKey);
if (!expectedValue.equals(actual)) {
throw new IllegalStateException("env property [" + envKey + "] mismatch (got [" + actual + "], expected [" + expectedValue + "]");
throw new IllegalStateException("env property [" + envKey + "] mismatch "
+ "(got [" + actual + "], expected [" + expectedValue + "]");
}
}

@ -24,7 +24,6 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -118,12 +117,12 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
private Map<String, String> systemPropertyVariables;
/**
* List of Environment variables that should be associated with the forked process used to run the
* application.
* <p>NOTE: the use of Environment variables means that processes will be started by forking a
* new JVM.
* List of Environment variables that should be associated with the forked process
* used to run the application. NOTE: the use of Environment variables means that
* processes will be started by forking a new JVM.
* @since 2.1
*/
@Parameter(property = "spring-boot.run.environmentVariables")
@Parameter
private Map<String, String> environmentVariables;
/**
@ -231,7 +230,6 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
return (this.environmentVariables != null && !this.environmentVariables.isEmpty());
}
private boolean hasWorkingDirectorySet() {
return this.workingDirectory != null;
}
@ -273,22 +271,19 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
private void doRunWithForkedJvm(String startClassName)
throws MojoExecutionException, MojoFailureException {
List<String> args = new ArrayList<>();
Map<String, String> envVariables = new LinkedHashMap<>();
addAgents(args);
addJvmArgs(args);
addClasspath(args);
args.add(startClassName);
addArgs(args);
addEnvironmentVariables(envVariables);
runWithForkedJvm(this.workingDirectory, args, envVariables);
runWithForkedJvm(this.workingDirectory, args, determineEnvironmentVariables());
}
/**
* Run with a forked VM, using the specified command line arguments.
* @param workingDirectory the working directory of the forked JVM
* @param args the arguments (JVM arguments and application arguments)
* @param environmentVariables the environment variables;
* @param environmentVariables the environment variables
* @throws MojoExecutionException in case of MOJO execution errors
* @throws MojoFailureException in case of MOJO failures
*/
@ -316,27 +311,24 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
return runArguments;
}
/**
* Resolve the environment variables to use.
*
* @return a {@link EnvVariables} defining the environment variables
*/
protected EnvVariables resolveEnvVariables() {
return new EnvVariables(this.environmentVariables);
}
private void addArgs(List<String> args) {
RunArguments applicationArguments = resolveApplicationArguments();
Collections.addAll(args, applicationArguments.asArray());
logArguments("Application argument(s): ", this.arguments);
}
private void addEnvironmentVariables(Map<String, String> environmentVariables) {
private Map<String, String> determineEnvironmentVariables() {
EnvVariables envVariables = resolveEnvVariables();
environmentVariables.putAll(envVariables.asMap());
logArguments("Environment variable(s): ", envVariables.asArray());
return envVariables.asMap();
}
/**

@ -29,53 +29,39 @@ import java.util.Map;
*/
class EnvVariables {
private static final String SPACE = "=";
private static final String NO_VALUE = "";
private final Map<String, String> variables;
private final Map<String, String> args = new LinkedHashMap<>();
EnvVariables(Map<String, String> args) {
this.args.putAll(getArgs(args));
}
Map<String, String> asMap() {
return Collections.unmodifiableMap(this.args);
}
String[] asArray() {
List<String> args = new ArrayList<>(this.args.size());
for (Map.Entry<String, String> arg : this.args.entrySet()) {
args.add(arg.getKey() + SPACE + arg.getValue());
}
return args.toArray(new String[args.size()]);
EnvVariables(Map<String, String> variables) {
this.variables = parseEnvVariables(variables);
}
private Map<String, String> getArgs(Map<String, String> args) {
private static Map<String, String> parseEnvVariables(Map<String, String> args) {
if (args == null || args.isEmpty()) {
return Collections.emptyMap();
}
Map<String, String> result = new LinkedHashMap<>();
for (Map.Entry<String, String> e : args.entrySet()) {
if (hasText(e.getKey())) {
if (e.getKey() != null) {
result.put(e.getKey(), getValue(e.getValue()));
}
}
return result;
}
private String getValue(String value) {
if (hasText(value)) {
return value;
}
return NO_VALUE;
private static String getValue(String value) {
return (value != null ? value : "");
}
private boolean hasText(String source) {
return source != null && !source.trim().isEmpty();
public Map<String, String> asMap() {
return Collections.unmodifiableMap(this.variables);
}
public String[] asArray() {
List<String> args = new ArrayList<>(this.variables.size());
for (Map.Entry<String, String> arg : this.variables.entrySet()) {
args.add(arg.getKey() + "=" + arg.getValue());
}
return args.toArray(new String[0]);
}
}

@ -66,14 +66,15 @@ public class RunMojo extends AbstractRunMojo {
}
@Override
protected void runWithForkedJvm(File workingDirectory, List<String> args, Map<String, String> environmentVariables)
protected void runWithForkedJvm(File workingDirectory, List<String> args,
Map<String, String> environmentVariables)
throws MojoExecutionException {
try {
RunProcess runProcess = new RunProcess(workingDirectory,
new JavaExecutable().toString());
Runtime.getRuntime()
.addShutdownHook(new Thread(new RunProcessKiller(runProcess)));
int exitCode = runProcess.run(true, args.toArray(new String[0]), environmentVariables);
int exitCode = runProcess.run(true, args, environmentVariables);
if (exitCode == 0 || exitCode == EXIT_CODE_SIGINT) {
return;
}

@ -47,7 +47,6 @@ import org.springframework.boot.loader.tools.RunProcess;
* stopped after.
*
* @author Stephane Nicoll
* @author Dmytro Nosan
* @since 1.3.0
* @see StopMojo
*/
@ -90,7 +89,8 @@ public class StartMojo extends AbstractRunMojo {
private final Object lock = new Object();
@Override
protected void runWithForkedJvm(File workingDirectory, List<String> args, Map<String, String> environmentVariables)
protected void runWithForkedJvm(File workingDirectory, List<String> args,
Map<String, String> environmentVariables)
throws MojoExecutionException, MojoFailureException {
RunProcess runProcess = runProcess(workingDirectory, args, environmentVariables);
try {
@ -102,12 +102,13 @@ public class StartMojo extends AbstractRunMojo {
}
}
private RunProcess runProcess(File workingDirectory, List<String> args, Map<String, String> environmentVariables)
private RunProcess runProcess(File workingDirectory, List<String> args,
Map<String, String> environmentVariables)
throws MojoExecutionException {
try {
RunProcess runProcess = new RunProcess(workingDirectory,
new JavaExecutable().toString());
runProcess.run(false, args.toArray(new String[0]), environmentVariables);
runProcess.run(false, args, environmentVariables);
return runProcess;
}
catch (Exception ex) {

@ -0,0 +1,50 @@
-----
Using environment variables
-----
Dmytro Nosan
-----
2018-04-08
-----
Environment variables can be specified using the <<<environmentVariables>>> attribute.
The following sets the 'ENV1', 'ENV2', 'ENV3', 'ENV4' env variables:
---
<project>
...
<build>
...
<plugins>
...
<plugin>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<configuration>
<environmentVariables>
<ENV1>5000</ENV1>
<ENV2>Some Text</ENV2>
<ENV3/>
<ENV4></ENV4>
</environmentVariables>
</configuration>
...
</plugin>
...
</plugins>
...
</build>
...
</project>
---
If the value is empty or not defined (i.e. <<<<MY_ENV/>>>>), the env variable is set
with an empty String as the value.
Any String typed Maven variable can be passed as system properties. Any attempt to pass
any other Maven variable type (e.g. a <<<List>>> or a <<<URL>>> variable) will cause the
variable expression to be passed literally (unevaluated).
Environment variables defined this way take precedence over existing values.

@ -1,43 +0,0 @@
-----
Specify environment variables
-----
Dmytro Nosan
-----
2018-04-08
-----
The environmnet variables to use for a particular application can be specified using the <<<environmentVariables>>>
argument. The following configuration enables the 'ENV1', 'ENV2', 'ENV3', 'ENV4' env variables:
---
<project>
...
<build>
...
<plugins>
...
<plugin>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<configuration>
<environmentVariables>
<ENV1>5000</ENV1>
<ENV2>Some Text</ENV2>
<ENV3/>
<ENV4></ENV4>
</environmentVariables>
</configuration>
...
</plugin>
...
</plugins>
...
</build>
...
</project>
---
Note that since you specified some Environment variables, the process is forked automatically.

@ -54,14 +54,14 @@ Spring Boot Maven Plugin
* {{{./examples/run-system-properties.html}Using system properties}}
* {{{./examples/run-env-variables.html}Using environment variables}}
* {{{./examples/it-random-port.html}Random port for integration tests}}
* {{{./examples/it-skip.html}Skip integration tests}}
* {{{./examples/run-profiles.html}Specify active profiles}}
* {{{./examples/run-with-env.html}Specify Environment variables}}
* {{{./examples/build-info.html}Generate build information}}
* {{{./examples/custom-layout.html}Custom layout}}

@ -140,11 +140,12 @@ mvn spring-boot:run
If you need to specify some JVM arguments (i.e. for debugging purposes), you can use
the <<<jvmArguments>>> parameter, see {{{./examples/run-debug.html}Debug the application}}
for more details. There is also explicit support
{{{./examples/run-system-properties.html}for system properties}} and
{{{./examples/run-with-env.html}environment variables}}. As a convenience, the profiles
to enable are handled by a specific property (<<<profiles>>>), see
{{{./examples/run-profiles.html}Specify active profiles}}.
for more details. There is also explicit support for
{{{./examples/run-system-properties.html}system properties}} and
{{{./examples/run-env-variables.html}environment variables}}.
As a convenience, the profiles to enable are handled by a specific property (
<<<profiles>>>), see {{{./examples/run-profiles.html}Specify active profiles}}.
Spring Boot 1.3 has introduced <<<devtools>>>, a module to improve the development-time
experience when working on Spring Boot applications. To enable it, just add the following

@ -12,10 +12,10 @@
<item name="Exclude a dependency" href="examples/exclude-dependency.html"/>
<item name="Debug the application" href="examples/run-debug.html"/>
<item name="Using system properties" href="examples/run-system-properties.html"/>
<item name="Using environment variable" href="examples/run-env-variables.html"/>
<item name="Random port for integration tests" href="examples/it-random-port.html"/>
<item name="Skip integration tests" href="examples/it-skip.html"/>
<item name="Specify active profiles" href="examples/run-profiles.html"/>
<item name="Specify environment variables" href="examples/run-with-env.html"/>
<item name="Generate build information" href="examples/build-info.html"/>
<item name="Custom layout" href="examples/custom-layout.html"/>
</menu>

@ -22,6 +22,7 @@ import java.util.Map;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
/**
* Tests for {@link EnvVariables}.
@ -33,40 +34,29 @@ public class EnvVariablesTests {
@Test
public void asNull() {
Map<String, String> args = new EnvVariables(null).asMap();
assertThat(args).hasSize(0);
assertThat(args).isEmpty();
}
@Test
public void asArray() {
assertThat(new EnvVariables(getTestArgs()).asArray())
.contains("key=My Value")
.contains("key1= tt ")
.contains("key2=")
.contains("key3=");
.contains("key=My Value", "key1= tt ", "key2= ", "key3=");
}
@Test
public void asMap() {
assertThat(new EnvVariables(getTestArgs()).asMap())
.containsEntry("key", "My Value")
.containsEntry("key1", " tt ")
.containsEntry("key2", "")
.containsEntry("key3", "");
assertThat(new EnvVariables(getTestArgs()).asMap()).containsExactly(
entry("key", "My Value"), entry("key1", " tt "), entry("key2", " "),
entry("key3", ""));
}
private Map<String, String> getTestArgs() {
Map<String, String> args = new LinkedHashMap<>();
args.put("key", "My Value");
//should not be trimmed
args.put("key1", " tt ");
args.put("key2", " ");
args.put("key3", null);
return args;
}
}

Loading…
Cancel
Save