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
This commit is contained in:
Stephane Nicoll 2016-08-31 12:10:35 +02:00
parent 7765d31edd
commit ff48a88b91
7 changed files with 174 additions and 27 deletions

View File

@ -0,0 +1,33 @@
<?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>

View File

@ -0,0 +1,25 @@
/*
* 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 {
}

View File

@ -0,0 +1,25 @@
/*
* 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");
}
}

View File

@ -0,0 +1,6 @@
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")

View File

@ -140,7 +140,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
/**
* 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
*/
@Parameter(property = "fork")
@ -160,23 +161,6 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
@Parameter(defaultValue = "false")
private boolean skip;
/**
* Specify if the application process should be forked.
* @return {@code true} if the application process should be forked
*/
protected boolean isFork() {
return (Boolean.TRUE.equals(this.fork)
|| (this.fork == null && (hasAgent() || hasJvmArgs())));
}
private boolean hasAgent() {
return (this.agent != null && this.agent.length > 0);
}
private boolean hasJvmArgs() {
return (this.jvmArguments != null && this.jvmArguments.length() > 0);
}
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
if (this.skip) {
@ -187,6 +171,32 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
run(startClassName);
}
/**
* Specify if the application process should be forked.
* @return {@code true} if the application process should be forked
*/
protected boolean isFork() {
return (Boolean.TRUE.equals(this.fork)
|| (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() {
return (this.agent != null && this.agent.length > 0);
}
private boolean hasJvmArgs() {
return (this.jvmArguments != null && this.jvmArguments.length() > 0);
}
private void findAgent() {
try {
if (this.agent == null || this.agent.length == 0) {
@ -221,17 +231,26 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
doRunWithForkedJvm(startClassName);
}
else {
if (hasAgent()) {
getLog().warn("Fork mode disabled, ignoring agent");
}
if (hasJvmArgs()) {
getLog().warn("Fork mode disabled, ignoring JVM argument(s) ["
+ this.jvmArguments + "]");
}
logDisabledFork();
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)
throws MojoExecutionException, MojoFailureException {
List<String> args = new ArrayList<String>();

View File

@ -16,6 +16,7 @@
package org.springframework.boot.maven;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
@ -41,6 +42,26 @@ public class RunMojo extends AbstractRunMojo {
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
protected void runWithForkedJvm(List<String> args) throws MojoExecutionException {
try {
@ -92,6 +113,24 @@ public class RunMojo extends AbstractRunMojo {
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 final RunProcess runProcess;

View File

@ -128,7 +128,7 @@ 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' 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
the <<<jvmArguments>>> parameter, see {{{./examples/run-debug.html}Debug the application}}
@ -164,7 +164,7 @@ spring.devtools.remote.restart.enabled=false
---
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:
---