From 4a25bae14306e3cdfc4f25bd08feb531bb00a6b4 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 5 Aug 2015 11:44:26 +0100 Subject: [PATCH] Allow additional paths that trigger a reload/restart to be configured Previously, only folders on the classpath would be watched and used to trigger a restart/reload of the application. This commit adds a new property spring.devtools.restart.additional-paths that can be used to configure additional paths that should be watched for changes. When a change occurs in one of those paths a restart or reload will be triggered, depending on the full restart exclude patterns configured via the existing spring.devtools.restart.exclude property. Closes gh-3469 --- .../autoconfigure/DevToolsProperties.java | 17 +++++++++++++++ .../LocalDevToolsAutoConfiguration.java | 6 ++++++ .../LocalDevToolsAutoConfigurationTests.java | 21 +++++++++++++++++++ .../appendix-application-properties.adoc | 1 + .../src/main/asciidoc/using-spring-boot.adoc | 18 ++++++++++++++-- 5 files changed, 61 insertions(+), 2 deletions(-) diff --git a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsProperties.java b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsProperties.java index 95bc08be07e..0a5c359acc6 100644 --- a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsProperties.java +++ b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsProperties.java @@ -16,6 +16,10 @@ package org.springframework.boot.devtools.autoconfigure; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.NestedConfigurationProperty; @@ -87,6 +91,11 @@ public class DevToolsProperties { */ private String triggerFile; + /** + * Additional paths to watch for changes. + */ + private List additionalPaths = new ArrayList(); + public boolean isEnabled() { return this.enabled; } @@ -127,6 +136,14 @@ public class DevToolsProperties { this.triggerFile = triggerFile; } + public List getAdditionalPaths() { + return this.additionalPaths; + } + + public void setAdditionalPaths(List additionalPaths) { + this.additionalPaths = additionalPaths; + } + } /** diff --git a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java index f1002b92a72..eb2f8a45816 100644 --- a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java +++ b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java @@ -16,7 +16,9 @@ package org.springframework.boot.devtools.autoconfigure; +import java.io.File; import java.net.URL; +import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -158,6 +160,10 @@ public class LocalDevToolsAutoConfiguration { if (StringUtils.hasLength(triggerFile)) { watcher.setTriggerFilter(new TriggerFileFilter(triggerFile)); } + List additionalPaths = restartProperties.getAdditionalPaths(); + for (File path : additionalPaths) { + watcher.addSourceFolder(path.getAbsoluteFile()); + } return watcher; } diff --git a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java index 82fbfdc5992..4d7b6bf9f45 100644 --- a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java +++ b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.devtools.autoconfigure; +import java.io.File; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -45,7 +46,9 @@ import org.springframework.util.SocketUtils; import org.thymeleaf.templateresolver.TemplateResolver; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasKey; import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.assertThat; import static org.mockito.Matchers.any; @@ -181,6 +184,24 @@ public class LocalDevToolsAutoConfigurationTests { assertThat(filter, instanceOf(TriggerFileFilter.class)); } + @Test + public void watchingAdditionalPaths() throws Exception { + Map properties = new HashMap(); + properties.put("spring.devtools.restart.additional-paths", + "src/main/java,src/test/java"); + this.context = initializeAndRun(Config.class, properties); + ClassPathFileSystemWatcher classPathWatcher = this.context + .getBean(ClassPathFileSystemWatcher.class); + Object watcher = ReflectionTestUtils.getField(classPathWatcher, + "fileSystemWatcher"); + @SuppressWarnings("unchecked") + Map folders = (Map) ReflectionTestUtils.getField( + watcher, "folders"); + assertThat(folders.size(), is(equalTo(2))); + assertThat(folders, hasKey(new File("src/main/java").getAbsoluteFile())); + assertThat(folders, hasKey(new File("src/test/java").getAbsoluteFile())); + } + private ConfigurableApplicationContext initializeAndRun(Class config) { return initializeAndRun(config, Collections. emptyMap()); } diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 4d28ce6125a..fa673b9bf07 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -617,6 +617,7 @@ content into your application; rather pick only the properties that you need. # ---------------------------------------- # DEVTOOLS ({sc-spring-boot-devtools}/autoconfigure/DevToolsProperties.{sc-ext}[DevToolsProperties]) + spring.devtools.restart.additional-paths= # additional paths to watch for changes spring.devtools.restart.enabled=true # enable automatic restart spring.devtools.restart.exclude= # patterns that should be excluding for triggering a full restart spring.devtools.restart.poll-interval= # amount of time (in milliseconds) to wait between polling for classpath changes diff --git a/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc b/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc index 7e80fa9e621..ce29c7a8f92 100644 --- a/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc +++ b/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc @@ -894,12 +894,14 @@ commercially supported. +[[using-boot-devtools-restart-exclude]] ==== Excluding resources Certain resources don't necessarily need to trigger a restart when they are changed. For example, Thymeleaf templates can just be edited in-place. By default changing resources in `/META-INF/maven`, `/META-INF/resources` ,`/resources` ,`/static` ,`/public` or -`/templates` will not trigger a restart. If you want to customize these exclusions you -can use the `spring.devtools.restart.exclude` property. For example, to exclude only +`/templates` will not trigger a restart but will trigger a +<>. If you want to customize these exclusions +you can use the `spring.devtools.restart.exclude` property. For example, to exclude only `/static` and `/public` you would set the following: [indent=0] @@ -909,6 +911,18 @@ can use the `spring.devtools.restart.exclude` property. For example, to exclude +[[using-boot-devtools-restart-additional-paths]] +==== Watching additional paths +You may want your application to be restarted or reloaded when you make changes to files +that are not on the classpath. To do so, use the +`spring.devtools.restart.additional-paths` property to configure additional paths to watch +for changes. You can use the `spring.devtools.restart.exclude` property +<> to control whether changes +beneath the additional paths will trigger a full restart or just a +<>. + + + [[using-boot-devtools-restart-disable]] ==== Disabling restart If you don't want to use the restart feature you can disable it using the