From 95f7e3ca37b3d8139f7a5e299f1a96d5af509af1 Mon Sep 17 00:00:00 2001 From: Dmytro Nosan Date: Mon, 9 Apr 2018 00:11:27 +0300 Subject: [PATCH 1/2] Add support for environment variables See gh-12800 --- .../src/main/asciidoc/howto.adoc | 8 ++ .../boot/loader/tools/RunProcess.java | 12 ++- .../src/it/run-envargs/pom.xml | 38 +++++++++ .../main/java/org/test/SampleApplication.java | 40 +++++++++ .../src/it/run-envargs/verify.groovy | 3 + .../boot/maven/AbstractRunMojo.java | 44 +++++++++- .../boot/maven/EnvVariables.java | 81 +++++++++++++++++++ .../springframework/boot/maven/RunMojo.java | 6 +- .../springframework/boot/maven/StartMojo.java | 10 ++- .../src/site/apt/examples/run-with-env.apt.vm | 43 ++++++++++ .../src/site/apt/index.apt | 2 + .../src/site/apt/usage.apt.vm | 9 ++- .../src/site/site.xml | 1 + .../boot/maven/EnvVariablesTests.java | 72 +++++++++++++++++ 14 files changed, 354 insertions(+), 15 deletions(-) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/pom.xml create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/src/main/java/org/test/SampleApplication.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/verify.groovy create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/EnvVariables.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-with-env.apt.vm create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/EnvVariablesTests.java diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc index 7e43d55146..75cbcda8a4 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -2771,6 +2771,14 @@ 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` diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java index 03b2a90cf4..e8b460cc7b 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java @@ -20,6 +20,8 @@ import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.Map; /** * Utility used to run a process. @@ -28,6 +30,7 @@ import java.util.Collection; * @author Dave Syer * @author Andy Wilkinson * @author Stephane Nicoll + * @author Dmytro Nosan * @since 1.1.0 */ public class RunProcess { @@ -63,14 +66,19 @@ public class RunProcess { } public int run(boolean waitForProcess, String... args) throws IOException { - return run(waitForProcess, Arrays.asList(args)); + return run(waitForProcess, Arrays.asList(args), Collections.emptyMap()); } - protected int run(boolean waitForProcess, Collection args) + public int run(boolean waitForProcess, String[] args, Map environmentVariables) throws IOException { + return run(waitForProcess, Arrays.asList(args), environmentVariables); + } + + protected int run(boolean waitForProcess, Collection args, Map environmentVariables) throws IOException { ProcessBuilder builder = new ProcessBuilder(this.command); builder.directory(this.workingDirectory); builder.command().addAll(args); + builder.environment().putAll(environmentVariables); builder.redirectErrorStream(true); builder.inheritIO(); try { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/pom.xml new file mode 100644 index 0000000000..b14692f606 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + org.springframework.boot.maven.it + run-envargs + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + @java.version@ + @java.version@ + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + package + + run + + + + 5000 + Some Text + + + + + + + + + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/src/main/java/org/test/SampleApplication.java new file mode 100644 index 0000000000..044ec36035 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.test; + +public class SampleApplication { + + + public static void main(String[] args) { + assertEnvValue("ENV1", "5000"); + assertEnvValue("ENV2", "Some Text"); + assertEnvValue("ENV3", ""); + assertEnvValue("ENV4", ""); + + System.out.println("I haz been run"); + + } + + + 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 + "]"); + } + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/verify.groovy b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/verify.groovy new file mode 100644 index 0000000000..841c4a97de --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/verify.groovy @@ -0,0 +1,3 @@ +def file = new File(basedir, "build.log") +return file.text.contains("I haz been run") + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java index 2eb74cad2b..6c2e76ea13 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java @@ -24,6 +24,7 @@ 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; @@ -48,6 +49,7 @@ import org.springframework.boot.loader.tools.MainClassFinder; * @author Stephane Nicoll * @author David Liu * @author Daniel Young + * @author Dmytro Nosan * @see RunMojo * @see StartMojo */ @@ -115,6 +117,15 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { @Parameter private Map systemPropertyVariables; + /** + * 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. + */ + @Parameter(property = "spring-boot.run.environmentVariables") + private Map environmentVariables; + /** * Arguments that should be passed to the application. On command line use commas to * separate multiple arguments. @@ -203,7 +214,7 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { * @see #logDisabledFork() */ protected boolean enableForkByDefault() { - return hasAgent() || hasJvmArgs() || hasWorkingDirectorySet(); + return hasAgent() || hasJvmArgs() || hasEnvVariables() || hasWorkingDirectorySet(); } private boolean hasAgent() { @@ -216,6 +227,11 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { && !this.systemPropertyVariables.isEmpty()); } + private boolean hasEnvVariables() { + return (this.environmentVariables != null && !this.environmentVariables.isEmpty()); + } + + private boolean hasWorkingDirectorySet() { return this.workingDirectory != null; } @@ -257,22 +273,27 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { private void doRunWithForkedJvm(String startClassName) throws MojoExecutionException, MojoFailureException { List args = new ArrayList<>(); + Map envVariables = new LinkedHashMap<>(); addAgents(args); addJvmArgs(args); addClasspath(args); args.add(startClassName); addArgs(args); - runWithForkedJvm(this.workingDirectory, args); + addEnvironmentVariables(envVariables); + runWithForkedJvm(this.workingDirectory, args, envVariables); } + /** * 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; * @throws MojoExecutionException in case of MOJO execution errors * @throws MojoFailureException in case of MOJO failures */ - protected abstract void runWithForkedJvm(File workingDirectory, List args) + protected abstract void runWithForkedJvm(File workingDirectory, List args, + Map environmentVariables) throws MojoExecutionException, MojoFailureException; /** @@ -295,12 +316,29 @@ 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 args) { RunArguments applicationArguments = resolveApplicationArguments(); Collections.addAll(args, applicationArguments.asArray()); logArguments("Application argument(s): ", this.arguments); } + private void addEnvironmentVariables(Map environmentVariables) { + EnvVariables envVariables = resolveEnvVariables(); + environmentVariables.putAll(envVariables.asMap()); + logArguments("Environment variable(s): ", envVariables.asArray()); + } + /** * Resolve the JVM arguments to use. * @return a {@link RunArguments} defining the JVM arguments diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/EnvVariables.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/EnvVariables.java new file mode 100644 index 0000000000..0ee67f00e9 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/EnvVariables.java @@ -0,0 +1,81 @@ +/* + * Copyright 2012-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.maven; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * Utility class for working with Env variables. + * + * @author Dmytro Nosan + */ +class EnvVariables { + + private static final String SPACE = "="; + private static final String NO_VALUE = ""; + + private final Map args = new LinkedHashMap<>(); + + EnvVariables(Map args) { + this.args.putAll(getArgs(args)); + } + + Map asMap() { + return Collections.unmodifiableMap(this.args); + } + + String[] asArray() { + List args = new ArrayList<>(this.args.size()); + for (Map.Entry arg : this.args.entrySet()) { + args.add(arg.getKey() + SPACE + arg.getValue()); + } + return args.toArray(new String[args.size()]); + } + + + private Map getArgs(Map args) { + + if (args == null || args.isEmpty()) { + return Collections.emptyMap(); + } + + Map result = new LinkedHashMap<>(); + for (Map.Entry e : args.entrySet()) { + if (hasText(e.getKey())) { + result.put(e.getKey(), getValue(e.getValue())); + } + } + return result; + } + + private String getValue(String value) { + if (hasText(value)) { + return value; + } + return NO_VALUE; + } + + private boolean hasText(String source) { + return source != null && !source.trim().isEmpty(); + } + + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java index 1280b88162..6231252c6b 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java @@ -20,6 +20,7 @@ import java.io.File; import java.net.URL; import java.net.URLClassLoader; import java.util.List; +import java.util.Map; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Execute; @@ -34,6 +35,7 @@ import org.springframework.boot.loader.tools.RunProcess; * Run an executable archive application. * * @author Phillip Webb + * @author Dmytro Nosan * @author Stephane Nicoll * @author Andy Wilkinson */ @@ -64,14 +66,14 @@ public class RunMojo extends AbstractRunMojo { } @Override - protected void runWithForkedJvm(File workingDirectory, List args) + protected void runWithForkedJvm(File workingDirectory, List args, Map 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])); + int exitCode = runProcess.run(true, args.toArray(new String[0]), environmentVariables); if (exitCode == 0 || exitCode == EXIT_CODE_SIGINT) { return; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java index 9a27ca8479..5760e04f90 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java @@ -23,6 +23,7 @@ import java.net.ConnectException; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.concurrent.Callable; import javax.management.MBeanServerConnection; @@ -46,6 +47,7 @@ import org.springframework.boot.loader.tools.RunProcess; * stopped after. * * @author Stephane Nicoll + * @author Dmytro Nosan * @since 1.3.0 * @see StopMojo */ @@ -88,9 +90,9 @@ public class StartMojo extends AbstractRunMojo { private final Object lock = new Object(); @Override - protected void runWithForkedJvm(File workingDirectory, List args) + protected void runWithForkedJvm(File workingDirectory, List args, Map environmentVariables) throws MojoExecutionException, MojoFailureException { - RunProcess runProcess = runProcess(workingDirectory, args); + RunProcess runProcess = runProcess(workingDirectory, args, environmentVariables); try { waitForSpringApplication(); } @@ -100,12 +102,12 @@ public class StartMojo extends AbstractRunMojo { } } - private RunProcess runProcess(File workingDirectory, List args) + private RunProcess runProcess(File workingDirectory, List args, Map environmentVariables) throws MojoExecutionException { try { RunProcess runProcess = new RunProcess(workingDirectory, new JavaExecutable().toString()); - runProcess.run(false, args.toArray(new String[0])); + runProcess.run(false, args.toArray(new String[0]), environmentVariables); return runProcess; } catch (Exception ex) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-with-env.apt.vm b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-with-env.apt.vm new file mode 100644 index 0000000000..7bbe5b7b93 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-with-env.apt.vm @@ -0,0 +1,43 @@ + ----- + Specify environment variables + ----- +Dmytro Nosan + ----- + 2018-04-08 + ----- + + The environmnet variables to use for a particular application can be specified using the <<>> + argument. The following configuration enables the 'ENV1', 'ENV2', 'ENV3', 'ENV4' env variables: + +--- + + ... + + ... + + ... + + ${project.groupId} + ${project.artifactId} + ${project.version} + + + 5000 + Some Text + + + + + ... + + ... + + ... + + ... + +--- + + Note that since you specified some Environment variables, the process is forked automatically. + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt index f3e47a5d96..5ed3cc8a37 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt @@ -60,6 +60,8 @@ Spring Boot Maven Plugin * {{{./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}} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm index ffa09b3e1f..1bf825f0ad 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm @@ -135,14 +135,15 @@ mvn spring-boot:run By default the application is executed directly from the Maven JVM. If you need to run in a forked process you can use the 'fork' option. Forking will also occur if the - 'jvmArguments', 'systemPropertyVariables' or 'agent' options are specified, or if - devtools is present. + 'jvmArguments', 'systemPropertyVariables', 'environmentVariables' or 'agent' options + are specified, or if devtools is present. If you need to specify some JVM arguments (i.e. for debugging purposes), you can use the <<>> 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}}. As a convenience, the - profiles to enable are handled by a specific property (<<>>), see + {{{./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 (<<>>), see {{{./examples/run-profiles.html}Specify active profiles}}. Spring Boot 1.3 has introduced <<>>, a module to improve the development-time diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml index 5e1157ab54..e0000dd907 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml @@ -15,6 +15,7 @@ + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/EnvVariablesTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/EnvVariablesTests.java new file mode 100644 index 0000000000..595fe24b7a --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/EnvVariablesTests.java @@ -0,0 +1,72 @@ +/* + * Copyright 2012-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.maven; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link EnvVariables}. + * + * @author Dmytro Nosan + */ +public class EnvVariablesTests { + + @Test + public void asNull() { + Map args = new EnvVariables(null).asMap(); + assertThat(args).hasSize(0); + } + + + @Test + public void asArray() { + assertThat(new EnvVariables(getTestArgs()).asArray()) + .contains("key=My Value") + .contains("key1= tt ") + .contains("key2=") + .contains("key3="); + } + + @Test + public void asMap() { + assertThat(new EnvVariables(getTestArgs()).asMap()) + .containsEntry("key", "My Value") + .containsEntry("key1", " tt ") + .containsEntry("key2", "") + .containsEntry("key3", ""); + } + + + private Map getTestArgs() { + Map 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; + } + + + + +} From 40b7e02793184c377391d501dd5c843a31e1d1e4 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 24 Apr 2018 15:44:59 +0200 Subject: [PATCH 2/2] Polish "Add support for environment variables" Closes gh-12800 --- .../src/main/asciidoc/howto.adoc | 8 --- .../boot/loader/tools/RunProcess.java | 8 +-- .../main/java/org/test/SampleApplication.java | 8 ++- .../boot/maven/AbstractRunMojo.java | 26 ++++------ .../boot/maven/EnvVariables.java | 46 ++++++----------- .../springframework/boot/maven/RunMojo.java | 5 +- .../springframework/boot/maven/StartMojo.java | 9 ++-- .../apt/examples/run-env-variables.apt.vm | 50 +++++++++++++++++++ .../src/site/apt/examples/run-with-env.apt.vm | 43 ---------------- .../src/site/apt/index.apt | 4 +- .../src/site/apt/usage.apt.vm | 11 ++-- .../src/site/site.xml | 2 +- .../boot/maven/EnvVariablesTests.java | 22 +++----- 13 files changed, 103 insertions(+), 139 deletions(-) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-env-variables.apt.vm delete mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-with-env.apt.vm diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc index 75cbcda8a4..7e43d55146 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -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` diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java index e8b460cc7b..36f4ba5dfd 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java @@ -69,12 +69,8 @@ public class RunProcess { return run(waitForProcess, Arrays.asList(args), Collections.emptyMap()); } - public int run(boolean waitForProcess, String[] args, Map environmentVariables) throws IOException { - return run(waitForProcess, Arrays.asList(args), environmentVariables); - } - - protected int run(boolean waitForProcess, Collection args, Map environmentVariables) - throws IOException { + public int run(boolean waitForProcess, Collection args, + Map environmentVariables) throws IOException { ProcessBuilder builder = new ProcessBuilder(this.command); builder.directory(this.workingDirectory); builder.command().addAll(args); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/src/main/java/org/test/SampleApplication.java index 044ec36035..c60eabec39 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/src/main/java/org/test/SampleApplication.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/src/main/java/org/test/SampleApplication.java @@ -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 + "]"); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java index 6c2e76ea13..74767347c5 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java @@ -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 systemPropertyVariables; /** - * 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. + * 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 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 args = new ArrayList<>(); - Map 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 args) { RunArguments applicationArguments = resolveApplicationArguments(); Collections.addAll(args, applicationArguments.asArray()); logArguments("Application argument(s): ", this.arguments); } - private void addEnvironmentVariables(Map environmentVariables) { + private Map determineEnvironmentVariables() { EnvVariables envVariables = resolveEnvVariables(); - environmentVariables.putAll(envVariables.asMap()); logArguments("Environment variable(s): ", envVariables.asArray()); + return envVariables.asMap(); } /** diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/EnvVariables.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/EnvVariables.java index 0ee67f00e9..a38d4876e1 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/EnvVariables.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/EnvVariables.java @@ -29,53 +29,39 @@ import java.util.Map; */ class EnvVariables { - private static final String SPACE = "="; - private static final String NO_VALUE = ""; + private final Map variables; - private final Map args = new LinkedHashMap<>(); - - EnvVariables(Map args) { - this.args.putAll(getArgs(args)); - } - - Map asMap() { - return Collections.unmodifiableMap(this.args); - } - - String[] asArray() { - List args = new ArrayList<>(this.args.size()); - for (Map.Entry arg : this.args.entrySet()) { - args.add(arg.getKey() + SPACE + arg.getValue()); - } - return args.toArray(new String[args.size()]); + EnvVariables(Map variables) { + this.variables = parseEnvVariables(variables); } - - private Map getArgs(Map args) { - + private static Map parseEnvVariables(Map args) { if (args == null || args.isEmpty()) { return Collections.emptyMap(); } - Map result = new LinkedHashMap<>(); for (Map.Entry 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 asMap() { + return Collections.unmodifiableMap(this.variables); } + public String[] asArray() { + List args = new ArrayList<>(this.variables.size()); + for (Map.Entry arg : this.variables.entrySet()) { + args.add(arg.getKey() + "=" + arg.getValue()); + } + return args.toArray(new String[0]); + } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java index 6231252c6b..cf75bd6b50 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java @@ -66,14 +66,15 @@ public class RunMojo extends AbstractRunMojo { } @Override - protected void runWithForkedJvm(File workingDirectory, List args, Map environmentVariables) + protected void runWithForkedJvm(File workingDirectory, List args, + Map 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; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java index 5760e04f90..151981c6c2 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java @@ -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 args, Map environmentVariables) + protected void runWithForkedJvm(File workingDirectory, List args, + Map 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 args, Map environmentVariables) + private RunProcess runProcess(File workingDirectory, List args, + Map 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) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-env-variables.apt.vm b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-env-variables.apt.vm new file mode 100644 index 0000000000..855fc8a329 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-env-variables.apt.vm @@ -0,0 +1,50 @@ + ----- + Using environment variables + ----- +Dmytro Nosan + ----- + 2018-04-08 + ----- + + Environment variables can be specified using the <<>> attribute. + The following sets the 'ENV1', 'ENV2', 'ENV3', 'ENV4' env variables: + +--- + + ... + + ... + + ... + + ${project.groupId} + ${project.artifactId} + ${project.version} + + + 5000 + Some Text + + + + + ... + + ... + + ... + + ... + +--- + + If the value is empty or not defined (i.e. <<<>>>), 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 <<>> or a <<>> variable) will cause the + variable expression to be passed literally (unevaluated). + + Environment variables defined this way take precedence over existing values. + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-with-env.apt.vm b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-with-env.apt.vm deleted file mode 100644 index 7bbe5b7b93..0000000000 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-with-env.apt.vm +++ /dev/null @@ -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 <<>> - argument. The following configuration enables the 'ENV1', 'ENV2', 'ENV3', 'ENV4' env variables: - ---- - - ... - - ... - - ... - - ${project.groupId} - ${project.artifactId} - ${project.version} - - - 5000 - Some Text - - - - - ... - - ... - - ... - - ... - ---- - - Note that since you specified some Environment variables, the process is forked automatically. - - diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt index 5ed3cc8a37..22fa6c63ca 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt @@ -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}} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm index 1bf825f0ad..f7cc89ed06 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm @@ -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 <<>> 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 (<<>>), 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 ( + <<>>), see {{{./examples/run-profiles.html}Specify active profiles}}. Spring Boot 1.3 has introduced <<>>, a module to improve the development-time experience when working on Spring Boot applications. To enable it, just add the following diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml index e0000dd907..89218fd978 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml @@ -12,10 +12,10 @@ + - diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/EnvVariablesTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/EnvVariablesTests.java index 595fe24b7a..21242e19b7 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/EnvVariablesTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/EnvVariablesTests.java @@ -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 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 getTestArgs() { Map 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; } - - - }