diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/using/devtools.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/using/devtools.adoc index ca344d9dc59..a0664e59ba6 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/using/devtools.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/using/devtools.adoc @@ -108,10 +108,8 @@ The way in which you cause the classpath to be updated depends on the tool that NOTE: If you are restarting with Maven or Gradle using the build plugin you must leave the `forking` set to `enabled`. If you disable forking, the isolated application classloader used by devtools will not be created and restarts will not operate properly. -TIP: Automatic restart works very well when used with LiveReload. -See the xref:using/devtools.adoc#using.devtools.livereload[] section for details. -If you use JRebel, automatic restarts are disabled in favor of dynamic class reloading. -Other devtools features (such as LiveReload and property overrides) can still be used. +TIP: If you use JRebel, automatic restarts are disabled in favor of dynamic class reloading. +Other devtools features (such as property overrides) can still be used. NOTE: DevTools relies on the application context's shutdown hook to close it during a restart. It does not work correctly if you have disabled the shutdown hook (`SpringApplication.setRegisterShutdownHook(false)`). @@ -287,11 +285,13 @@ If you find such a problem, you need to request a fix with the original authors. [[using.devtools.livereload]] == LiveReload +WARNING: Given its decrease in popularity and support, the LiveReload feature is deprecated as of Spring Boot 4.1.0 with no replacement. + The `spring-boot-devtools` module includes an embedded LiveReload server that can be used to trigger a browser refresh when a resource is changed. LiveReload browser extensions are freely available for Chrome, Firefox and Safari. You can find these extensions by searching 'LiveReload' in the marketplace or store of your chosen browser. -If you want to start the LiveReload server when your application runs, you can set the configprop:spring.devtools.livereload.enabled[] property to `true`. +If you want to start the LiveReload server when your application runs, you can set the `spring.devtools.livereload.enabled` property to `true`. NOTE: You can only run one LiveReload server at a time. Before starting your application, ensure that no other LiveReload servers are running. diff --git a/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsProperties.java b/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsProperties.java index b7ecb9ebb6b..5db413c1693 100644 --- a/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsProperties.java +++ b/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsProperties.java @@ -24,6 +24,7 @@ import java.util.List; import org.jspecify.annotations.Nullable; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.DeprecatedConfigurationProperty; import org.springframework.boot.context.properties.NestedConfigurationProperty; import org.springframework.util.StringUtils; @@ -200,6 +201,7 @@ public class DevToolsProperties { */ private int port = 35729; + @DeprecatedConfigurationProperty(reason = "Deprecated with no replacement", since = "4.1.0") public boolean isEnabled() { return this.enabled; } @@ -208,6 +210,7 @@ public class DevToolsProperties { this.enabled = enabled; } + @DeprecatedConfigurationProperty(reason = "Deprecated with no replacement", since = "4.1.0") public int getPort() { return this.port; } diff --git a/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java b/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java index 4392bf46eb4..add36fcdcea 100644 --- a/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java +++ b/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java @@ -37,7 +37,6 @@ import org.springframework.boot.devtools.classpath.PatternClassPathRestartStrate import org.springframework.boot.devtools.filewatch.FileSystemWatcher; import org.springframework.boot.devtools.filewatch.FileSystemWatcherFactory; import org.springframework.boot.devtools.filewatch.SnapshotStateRepository; -import org.springframework.boot.devtools.livereload.LiveReloadServer; import org.springframework.boot.devtools.restart.ConditionalOnInitializedRestarter; import org.springframework.boot.devtools.restart.RestartScope; import org.springframework.boot.devtools.restart.Restarter; @@ -71,18 +70,20 @@ public final class LocalDevToolsAutoConfiguration { */ @Configuration(proxyBeanMethods = false) @ConditionalOnBooleanProperty(name = "spring.devtools.livereload.enabled") + @SuppressWarnings("removal") static class LiveReloadConfiguration { @Bean @RestartScope @ConditionalOnMissingBean - LiveReloadServer liveReloadServer(DevToolsProperties properties) { - return new LiveReloadServer(properties.getLivereload().getPort(), - Restarter.getInstance().getThreadFactory()); + org.springframework.boot.devtools.livereload.LiveReloadServer liveReloadServer(DevToolsProperties properties) { + return new org.springframework.boot.devtools.livereload.LiveReloadServer( + properties.getLivereload().getPort(), Restarter.getInstance().getThreadFactory()); } @Bean - OptionalLiveReloadServer optionalLiveReloadServer(LiveReloadServer liveReloadServer) { + OptionalLiveReloadServer optionalLiveReloadServer( + org.springframework.boot.devtools.livereload.LiveReloadServer liveReloadServer) { return new OptionalLiveReloadServer(liveReloadServer); } @@ -160,6 +161,7 @@ public final class LocalDevToolsAutoConfiguration { } + @SuppressWarnings("removal") static class LiveReloadServerEventListener implements GenericApplicationListener { private final OptionalLiveReloadServer liveReloadServer; diff --git a/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/OptionalLiveReloadServer.java b/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/OptionalLiveReloadServer.java index 1931f4fab8f..1ca0dc0ae5e 100644 --- a/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/OptionalLiveReloadServer.java +++ b/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/OptionalLiveReloadServer.java @@ -30,7 +30,10 @@ import org.springframework.core.log.LogMessage; * * @author Phillip Webb * @since 1.3.0 + * @deprecated since 4.1.0 for removal in 4.3.0 with no replacement. */ +@Deprecated(since = "4.1.0", forRemoval = true) +@SuppressWarnings("removal") public class OptionalLiveReloadServer implements InitializingBean { private static final Log logger = LogFactory.getLog(OptionalLiveReloadServer.class); diff --git a/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/Connection.java b/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/Connection.java index a4b26198210..8019a19f1c8 100644 --- a/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/Connection.java +++ b/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/Connection.java @@ -40,6 +40,7 @@ import org.springframework.util.Assert; * @author Phillip Webb * @author Francis Lavoie */ +@SuppressWarnings("removal") class Connection { private static final Log logger = LogFactory.getLog(Connection.class); diff --git a/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/LiveReloadServer.java b/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/LiveReloadServer.java index 0e587afb3bd..4bebcede1b5 100644 --- a/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/LiveReloadServer.java +++ b/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/LiveReloadServer.java @@ -42,7 +42,9 @@ import org.springframework.util.Assert; * * @author Phillip Webb * @since 1.3.0 + * @deprecated since 4.1.0 for removal in 4.3.0 with no replacement. */ +@Deprecated(since = "4.1.0", forRemoval = true) public class LiveReloadServer { /** diff --git a/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/DelayedLiveReloadTrigger.java b/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/DelayedLiveReloadTrigger.java index 3ea02bfa16a..d84cdcbac2b 100644 --- a/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/DelayedLiveReloadTrigger.java +++ b/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/DelayedLiveReloadTrigger.java @@ -37,6 +37,7 @@ import org.springframework.util.Assert; * * @author Phillip Webb */ +@SuppressWarnings("removal") class DelayedLiveReloadTrigger implements Runnable { private static final long SHUTDOWN_TIME = 1000; diff --git a/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/RemoteClientConfiguration.java b/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/RemoteClientConfiguration.java index ef4f525f23d..b01ad14c9fd 100644 --- a/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/RemoteClientConfiguration.java +++ b/module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/RemoteClientConfiguration.java @@ -36,7 +36,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.devtools.autoconfigure.DevToolsProperties; import org.springframework.boot.devtools.autoconfigure.DevToolsProperties.Restart; -import org.springframework.boot.devtools.autoconfigure.OptionalLiveReloadServer; import org.springframework.boot.devtools.autoconfigure.RemoteDevToolsProperties; import org.springframework.boot.devtools.autoconfigure.RemoteDevToolsProperties.Proxy; import org.springframework.boot.devtools.autoconfigure.TriggerFileFilter; @@ -46,7 +45,6 @@ import org.springframework.boot.devtools.classpath.ClassPathRestartStrategy; import org.springframework.boot.devtools.classpath.PatternClassPathRestartStrategy; import org.springframework.boot.devtools.filewatch.FileSystemWatcher; import org.springframework.boot.devtools.filewatch.FileSystemWatcherFactory; -import org.springframework.boot.devtools.livereload.LiveReloadServer; import org.springframework.boot.devtools.restart.DefaultRestartInitializer; import org.springframework.boot.devtools.restart.RestartScope; import org.springframework.boot.devtools.restart.Restarter; @@ -71,6 +69,7 @@ import org.springframework.util.StringUtils; */ @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(DevToolsProperties.class) +@SuppressWarnings("removal") public class RemoteClientConfiguration implements InitializingBean { private static final Log logger = LogFactory.getLog(RemoteClientConfiguration.class); @@ -152,14 +151,14 @@ public class RemoteClientConfiguration implements InitializingBean { @Bean @RestartScope @ConditionalOnMissingBean - LiveReloadServer liveReloadServer() { - return new LiveReloadServer(this.properties.getLivereload().getPort(), - Restarter.getInstance().getThreadFactory()); + org.springframework.boot.devtools.livereload.LiveReloadServer liveReloadServer() { + return new org.springframework.boot.devtools.livereload.LiveReloadServer( + this.properties.getLivereload().getPort(), Restarter.getInstance().getThreadFactory()); } @Bean ApplicationListener liveReloadTriggeringClassPathChangedEventListener( - OptionalLiveReloadServer optionalLiveReloadServer) { + org.springframework.boot.devtools.autoconfigure.OptionalLiveReloadServer optionalLiveReloadServer) { return (event) -> { String url = this.remoteUrl + this.properties.getRemote().getContextPath(); this.executor.execute( @@ -168,8 +167,10 @@ public class RemoteClientConfiguration implements InitializingBean { } @Bean - OptionalLiveReloadServer optionalLiveReloadServer(ObjectProvider liveReloadServer) { - return new OptionalLiveReloadServer(liveReloadServer.getIfAvailable()); + org.springframework.boot.devtools.autoconfigure.OptionalLiveReloadServer optionalLiveReloadServer( + ObjectProvider liveReloadServer) { + return new org.springframework.boot.devtools.autoconfigure.OptionalLiveReloadServer( + liveReloadServer.getIfAvailable()); } final ExecutorService getExecutor() { diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java index 1c6ebe2a4dc..af6d37ba675 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java @@ -73,6 +73,7 @@ import static org.mockito.Mockito.reset; * @author Vladimir Tsanev */ @ExtendWith(MockRestarter.class) +@SuppressWarnings("removal") class LocalDevToolsAutoConfigurationTests { private @Nullable ConfigurableApplicationContext context; diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/OptionalLiveReloadServerTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/OptionalLiveReloadServerTests.java index 993e26ddebb..e284c0dedaf 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/OptionalLiveReloadServerTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/OptionalLiveReloadServerTests.java @@ -30,6 +30,7 @@ import static org.mockito.Mockito.never; * * @author Phillip Webb */ +@SuppressWarnings("removal") class OptionalLiveReloadServerTests { @Test diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/LiveReloadServerTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/LiveReloadServerTests.java index a3d4edc03f0..b32d6f3a868 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/LiveReloadServerTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/LiveReloadServerTests.java @@ -83,6 +83,7 @@ import static org.hamcrest.Matchers.not; * @author Phillip Webb * @author Andy Wilkinson */ +@SuppressWarnings("removal") class LiveReloadServerTests { private static final String HANDSHAKE = "{command: 'hello', " diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/DelayedLiveReloadTriggerTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/DelayedLiveReloadTriggerTests.java index 013c6c73cf7..f3dc5509a43 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/DelayedLiveReloadTriggerTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/DelayedLiveReloadTriggerTests.java @@ -44,6 +44,7 @@ import static org.mockito.Mockito.never; * @author Phillip Webb */ @ExtendWith(MockitoExtension.class) +@SuppressWarnings("removal") class DelayedLiveReloadTriggerTests { private static final String URL = "http://localhost:8080"; diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/RemoteClientConfigurationTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/RemoteClientConfigurationTests.java index a1af0cd6d6a..37ff6bef363 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/RemoteClientConfigurationTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/RemoteClientConfigurationTests.java @@ -104,6 +104,7 @@ class RemoteClientConfigurationTests { } @Test + @SuppressWarnings("removal") void liveReloadOnClassPathChanged() { configure("spring.devtools.livereload.enabled:true"); Set changeSet = new HashSet<>(); @@ -115,6 +116,7 @@ class RemoteClientConfigurationTests { } @Test + @SuppressWarnings("removal") void liveReloadDisabledByDefault() { configure(); assertThatExceptionOfType(NoSuchBeanDefinitionException.class) @@ -185,6 +187,7 @@ class RemoteClientConfigurationTests { } @Configuration(proxyBeanMethods = false) + @SuppressWarnings("removal") static class ClientConfig { @Bean