diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java index 5164d09dd34..d0809e76f8e 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java @@ -48,6 +48,7 @@ import org.springframework.context.annotation.Lazy; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.GenericApplicationListener; import org.springframework.core.ResolvableType; +import org.springframework.core.log.LogMessage; import org.springframework.util.StringUtils; /** @@ -107,17 +108,9 @@ public class LocalDevToolsAutoConfiguration { } @Bean - ApplicationListener restartingClassPathChangedEventListener( + RestartingClassPathChangeChangedEventListener restartingClassPathChangedEventListener( FileSystemWatcherFactory fileSystemWatcherFactory) { - return (event) -> { - if (event.isRestartRequired()) { - if (restarterLogger.isDebugEnabled()) { - restarterLogger.debug( - "Application restart required due to the following changes: " + event.getChangeSet()); - } - Restarter.getInstance().restart(new FileWatchingFailureHandler(fileSystemWatcherFactory)); - } - }; + return new RestartingClassPathChangeChangedEventListener(fileSystemWatcherFactory); } @Bean @@ -204,4 +197,25 @@ public class LocalDevToolsAutoConfiguration { } + static class RestartingClassPathChangeChangedEventListener implements ApplicationListener { + + private static final Log logger = LogFactory.getLog(RestartingClassPathChangeChangedEventListener.class); + + private final FileSystemWatcherFactory fileSystemWatcherFactory; + + RestartingClassPathChangeChangedEventListener(FileSystemWatcherFactory fileSystemWatcherFactory) { + this.fileSystemWatcherFactory = fileSystemWatcherFactory; + } + + @Override + public void onApplicationEvent(ClassPathChangedEvent event) { + if (event.isRestartRequired()) { + logger.info(LogMessage.format("Restarting due to %s", event.overview())); + logger.debug(LogMessage.of(() -> "Change set: %s" + event.getChangeSet())); + Restarter.getInstance().restart(new FileWatchingFailureHandler(this.fileSystemWatcherFactory)); + } + } + + } + } diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/classpath/ClassPathChangedEvent.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/classpath/ClassPathChangedEvent.java index 7d800ba6178..982a9e47145 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/classpath/ClassPathChangedEvent.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/classpath/ClassPathChangedEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 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. @@ -18,6 +18,8 @@ package org.springframework.boot.devtools.classpath; import java.util.Set; +import org.springframework.boot.devtools.filewatch.ChangedFile; +import org.springframework.boot.devtools.filewatch.ChangedFile.Type; import org.springframework.boot.devtools.filewatch.ChangedFiles; import org.springframework.context.ApplicationEvent; import org.springframework.core.style.ToStringCreator; @@ -71,4 +73,37 @@ public class ClassPathChangedEvent extends ApplicationEvent { .append("restartRequired", this.restartRequired).toString(); } + /** + * Return an overview of the changes that triggered this event. + * @return an overview of the changes + * @since 2.6.11 + */ + public String overview() { + int added = 0; + int deleted = 0; + int modified = 0; + for (ChangedFiles changedFiles : this.changeSet) { + for (ChangedFile changedFile : changedFiles) { + Type type = changedFile.getType(); + if (type == Type.ADD) { + added++; + } + else if (type == Type.DELETE) { + deleted++; + } + else if (type == Type.MODIFY) { + modified++; + } + } + } + int size = added + deleted + modified; + return String.format("%s (%s, %s, %s)", quantityOfUnit(size, "class path change"), + quantityOfUnit(added, "addition"), quantityOfUnit(deleted, "deletion"), + quantityOfUnit(modified, "modification")); + } + + private String quantityOfUnit(int quantity, String unit) { + return quantity + " " + ((quantity != 1) ? unit + "s" : unit); + } + } diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/ClassPathChangeUploader.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/ClassPathChangeUploader.java index b32a603d3fb..2fdf68f2067 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/ClassPathChangeUploader.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/ClassPathChangeUploader.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2022 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. @@ -91,14 +91,15 @@ public class ClassPathChangeUploader implements ApplicationListener "Unexpected " + statusCode + " response uploading class files"); - logUpload(classLoaderFiles); return; } catch (SocketException ex) { @@ -128,9 +129,8 @@ public class ClassPathChangeUploader implements ApplicationListener