From 6df10842d2bfb47bf728dd8c23c63aa1655b640d Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 12 Nov 2020 11:24:29 +0000 Subject: [PATCH] Allow Devtools to be enabled irrespective of the launching ClassLoader Closes gh-21424 --- .../restart/DefaultRestartInitializer.java | 32 ++++++++++++++++--- .../restart/RestartApplicationListener.java | 21 ++++++++++-- .../RestartApplicationListenerTests.java | 8 +++++ .../src/docs/asciidoc/using-spring-boot.adoc | 5 ++- 4 files changed, 59 insertions(+), 7 deletions(-) diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/DefaultRestartInitializer.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/DefaultRestartInitializer.java index 62d139c9430..2f502534dd8 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/DefaultRestartInitializer.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/DefaultRestartInitializer.java @@ -43,14 +43,38 @@ public class DefaultRestartInitializer implements RestartInitializer { } /** - * Returns if the thread is for a main invocation. By default checks the name of the - * thread and the context classloader. + * Returns if the thread is for a main invocation. By default {@link #isMain(Thread) + * checks the name of the thread} and {@link #isDevelopmentClassLoader(ClassLoader) + * the context classloader}. * @param thread the thread to check * @return {@code true} if the thread is a main invocation + * @see #isMainThread + * @see #isDevelopmentClassLoader(ClassLoader) */ protected boolean isMain(Thread thread) { - return thread.getName().equals("main") - && thread.getContextClassLoader().getClass().getName().contains("AppClassLoader"); + return isMainThread(thread) && isDevelopmentClassLoader(thread.getContextClassLoader()); + } + + /** + * Returns whether the given {@code thread} is considered to be the main thread. + * @param thread the thread to check + * @return {@code true} if it's the main thread, otherwise {@code false} + * @since 2.4.0 + */ + protected boolean isMainThread(Thread thread) { + return thread.getName().equals("main"); + } + + /** + * Returns whether the given {@code classLoader} is one that is typically used during + * development. + * @param classLoader the ClassLoader to check + * @return {@code true} if it's a ClassLoader typically used during development, + * otherwise {@code false} + * @since 2.4.0 + */ + protected boolean isDevelopmentClassLoader(ClassLoader classLoader) { + return classLoader.getClass().getName().contains("AppClassLoader"); } /** diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/RestartApplicationListener.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/RestartApplicationListener.java index 87be6ec2d15..fe2f84107e6 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/RestartApplicationListener.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/RestartApplicationListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -64,7 +64,24 @@ public class RestartApplicationListener implements ApplicationListener