Commit ff48a88b authored by Stephane Nicoll's avatar Stephane Nicoll

Enable fork more when devtools is present

This commit improves the run goal to automatically fork the process when
devtools is present and log a warning when fork has been disabled via
configuration since devtools will not work on a non-forked process.

We don't want devtools to kick in for integration tests so the logic has
been placed in `RunMojo` requiring a couple of protected methods to
override.

Closes gh-5137
parent 7765d31e
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.boot.maven.it</groupId>
<artifactId>run-devtools</artifactId>
<version>0.0.1.BUILD-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!-- Devtools cannot be added here but the project has the class
that the code is looking for -->
<build>
<plugins>
<plugin>
<groupId>@project.groupId@</groupId>
<artifactId>@project.artifactId@</artifactId>
<version>@project.version@</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<fork>false</fork>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
/*
* Copyright 2012-2016 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.devtools.restart;
/**
* Only meant to make sure that the plugin considers that devtools
* is present.
*/
public class Restarter {
}
\ No newline at end of file
/*
* Copyright 2012-2014 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) {
System.out.println("I haz been run");
}
}
import static org.junit.Assert.assertTrue
def file = new File(basedir, "build.log")
assertTrue 'Devtools should have been detected', file.text.contains('Fork mode disabled, devtools will be disabled')
assertTrue 'Application should have ran', file.text.contains("I haz been run")
...@@ -140,7 +140,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { ...@@ -140,7 +140,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
/** /**
* Flag to indicate if the run processes should be forked. {@code fork } is * Flag to indicate if the run processes should be forked. {@code fork } is
* automatically enabled if an agent or jvmArguments are specified. * automatically enabled if an agent or jvmArguments are specified, or if
* devtools is present.
* @since 1.2 * @since 1.2
*/ */
@Parameter(property = "fork") @Parameter(property = "fork")
...@@ -160,13 +161,32 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { ...@@ -160,13 +161,32 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
@Parameter(defaultValue = "false") @Parameter(defaultValue = "false")
private boolean skip; private boolean skip;
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
if (this.skip) {
getLog().debug("skipping run as per configuration.");
return;
}
final String startClassName = getStartClass();
run(startClassName);
}
/** /**
* Specify if the application process should be forked. * Specify if the application process should be forked.
* @return {@code true} if the application process should be forked * @return {@code true} if the application process should be forked
*/ */
protected boolean isFork() { protected boolean isFork() {
return (Boolean.TRUE.equals(this.fork) return (Boolean.TRUE.equals(this.fork)
|| (this.fork == null && (hasAgent() || hasJvmArgs()))); || (this.fork == null && enableForkByDefault()));
}
/**
* Specify if fork should be enabled by default.
* @return {@code true} if fork should be enabled by default
* @see #logDisabledFork()
*/
protected boolean enableForkByDefault() {
return hasAgent() || hasJvmArgs();
} }
private boolean hasAgent() { private boolean hasAgent() {
...@@ -177,16 +197,6 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { ...@@ -177,16 +197,6 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
return (this.jvmArguments != null && this.jvmArguments.length() > 0); return (this.jvmArguments != null && this.jvmArguments.length() > 0);
} }
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
if (this.skip) {
getLog().debug("skipping run as per configuration.");
return;
}
final String startClassName = getStartClass();
run(startClassName);
}
private void findAgent() { private void findAgent() {
try { try {
if (this.agent == null || this.agent.length == 0) { if (this.agent == null || this.agent.length == 0) {
...@@ -221,17 +231,26 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { ...@@ -221,17 +231,26 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
doRunWithForkedJvm(startClassName); doRunWithForkedJvm(startClassName);
} }
else { else {
if (hasAgent()) { logDisabledFork();
getLog().warn("Fork mode disabled, ignoring agent");
}
if (hasJvmArgs()) {
getLog().warn("Fork mode disabled, ignoring JVM argument(s) ["
+ this.jvmArguments + "]");
}
runWithMavenJvm(startClassName, resolveApplicationArguments().asArray()); runWithMavenJvm(startClassName, resolveApplicationArguments().asArray());
} }
} }
/**
* Log a warning indicating that fork mode has been explicitly disabled
* while some conditions are present that require to enable it.
* @see #enableForkByDefault()
*/
protected void logDisabledFork() {
if (hasAgent()) {
getLog().warn("Fork mode disabled, ignoring agent");
}
if (hasJvmArgs()) {
getLog().warn("Fork mode disabled, ignoring JVM argument(s) ["
+ this.jvmArguments + "]");
}
}
private void doRunWithForkedJvm(String startClassName) private void doRunWithForkedJvm(String startClassName)
throws MojoExecutionException, MojoFailureException { throws MojoExecutionException, MojoFailureException {
List<String> args = new ArrayList<String>(); List<String> args = new ArrayList<String>();
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package org.springframework.boot.maven; package org.springframework.boot.maven;
import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.util.List; import java.util.List;
...@@ -41,6 +42,26 @@ public class RunMojo extends AbstractRunMojo { ...@@ -41,6 +42,26 @@ public class RunMojo extends AbstractRunMojo {
private static final int EXIT_CODE_SIGINT = 130; private static final int EXIT_CODE_SIGINT = 130;
private static final String RESTARTER_CLASS_LOCATION = "org/springframework/boot/devtools/restart/Restarter.class";
/**
* Devtools presence flag to avoid checking for it several times per execution.
*/
private Boolean hasDevtools;
@Override
protected boolean enableForkByDefault() {
return super.enableForkByDefault() || hasDevtools();
}
@Override
protected void logDisabledFork() {
super.logDisabledFork();
if (hasDevtools()) {
getLog().warn("Fork mode disabled, devtools will be disabled");
}
}
@Override @Override
protected void runWithForkedJvm(List<String> args) throws MojoExecutionException { protected void runWithForkedJvm(List<String> args) throws MojoExecutionException {
try { try {
...@@ -92,6 +113,24 @@ public class RunMojo extends AbstractRunMojo { ...@@ -92,6 +113,24 @@ public class RunMojo extends AbstractRunMojo {
while (hasNonDaemonThreads); while (hasNonDaemonThreads);
} }
private boolean hasDevtools() {
if (this.hasDevtools == null) {
this.hasDevtools = checkForDevtools();
}
return this.hasDevtools;
}
private boolean checkForDevtools() {
try {
URL[] urls = getClassPathUrls();
URLClassLoader classLoader = new URLClassLoader(urls);
return (classLoader.findResource(RESTARTER_CLASS_LOCATION) != null);
}
catch (Exception ex) {
return false;
}
}
private static final class RunProcessKiller implements Runnable { private static final class RunProcessKiller implements Runnable {
private final RunProcess runProcess; private final RunProcess runProcess;
......
...@@ -128,7 +128,7 @@ mvn spring-boot:run ...@@ -128,7 +128,7 @@ mvn spring-boot:run
By default the application is executed directly from the Maven JVM. If you need to 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 in a forked process you can use the 'fork' option. Forking will also occur if the
'jvmArguments' or 'agent' options are specified. 'jvmArguments' 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 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}} the <<<jvmArguments>>> parameter, see {{{./examples/run-debug.html}Debug the application}}
...@@ -164,7 +164,7 @@ spring.devtools.remote.restart.enabled=false ...@@ -164,7 +164,7 @@ spring.devtools.remote.restart.enabled=false
--- ---
Prior to <<<devtools>>>, the plugin supported hot refreshing of resources by default which has Prior to <<<devtools>>>, the plugin supported hot refreshing of resources by default which has
now be disabled in favor of the solution described above. You can restore it at any time by now be disabled in favour of the solution described above. You can restore it at any time by
configuring your project: configuring your project:
--- ---
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment