Merge branch '3.1.x'

Closes gh-37921
This commit is contained in:
Andy Wilkinson 2023-10-18 10:07:14 +01:00
commit 9460f301b4
4 changed files with 55 additions and 9 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,6 +23,7 @@ import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.boot.context.event.ApplicationPreparedEvent; import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.context.event.ApplicationStartingEvent; import org.springframework.boot.context.event.ApplicationStartingEvent;
import org.springframework.boot.devtools.system.DevToolsEnablementDeducer;
import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
@ -66,7 +67,14 @@ public class RestartApplicationListener implements ApplicationListener<Applicati
String enabled = System.getProperty(ENABLED_PROPERTY); String enabled = System.getProperty(ENABLED_PROPERTY);
RestartInitializer restartInitializer = null; RestartInitializer restartInitializer = null;
if (enabled == null) { if (enabled == null) {
restartInitializer = new DefaultRestartInitializer(); if (implicitlyEnableRestart()) {
restartInitializer = new DefaultRestartInitializer();
}
else {
logger.info("Restart disabled due to context in which it is running");
Restarter.disable();
return;
}
} }
else if (Boolean.parseBoolean(enabled)) { else if (Boolean.parseBoolean(enabled)) {
restartInitializer = new DefaultRestartInitializer() { restartInitializer = new DefaultRestartInitializer() {
@ -96,6 +104,10 @@ public class RestartApplicationListener implements ApplicationListener<Applicati
} }
} }
boolean implicitlyEnableRestart() {
return DevToolsEnablementDeducer.shouldEnable(Thread.currentThread());
}
private void onApplicationPreparedEvent(ApplicationPreparedEvent event) { private void onApplicationPreparedEvent(ApplicationPreparedEvent event) {
Restarter.getInstance().prepare(event.getApplicationContext()); Restarter.getInstance().prepare(event.getApplicationContext());
} }

View File

@ -408,7 +408,7 @@ public class Restarter {
} }
void prepare(ConfigurableApplicationContext applicationContext) { void prepare(ConfigurableApplicationContext applicationContext) {
if (applicationContext != null && applicationContext.getParent() != null) { if (!this.enabled || (applicationContext != null && applicationContext.getParent() != null)) {
return; return;
} }
if (applicationContext instanceof GenericApplicationContext genericContext) { if (applicationContext instanceof GenericApplicationContext genericContext) {

View File

@ -65,7 +65,7 @@ class RestartApplicationListenerTests {
@Test @Test
void initializeWithReady() { void initializeWithReady() {
testInitialize(false); testInitialize(false, new ImplicitlyEnabledRestartApplicationListener());
assertThat(Restarter.getInstance()).hasFieldOrPropertyWithValue("args", ARGS); assertThat(Restarter.getInstance()).hasFieldOrPropertyWithValue("args", ARGS);
assertThat(Restarter.getInstance().isFinished()).isTrue(); assertThat(Restarter.getInstance().isFinished()).isTrue();
assertThat((List<?>) ReflectionTestUtils.getField(Restarter.getInstance(), "rootContexts")).isNotEmpty(); assertThat((List<?>) ReflectionTestUtils.getField(Restarter.getInstance(), "rootContexts")).isNotEmpty();
@ -73,7 +73,7 @@ class RestartApplicationListenerTests {
@Test @Test
void initializeWithFail() { void initializeWithFail() {
testInitialize(true); testInitialize(true, new ImplicitlyEnabledRestartApplicationListener());
assertThat(Restarter.getInstance()).hasFieldOrPropertyWithValue("args", ARGS); assertThat(Restarter.getInstance()).hasFieldOrPropertyWithValue("args", ARGS);
assertThat(Restarter.getInstance().isFinished()).isTrue(); assertThat(Restarter.getInstance().isFinished()).isTrue();
assertThat((List<?>) ReflectionTestUtils.getField(Restarter.getInstance(), "rootContexts")).isEmpty(); assertThat((List<?>) ReflectionTestUtils.getField(Restarter.getInstance(), "rootContexts")).isEmpty();
@ -82,7 +82,7 @@ class RestartApplicationListenerTests {
@Test @Test
void disableWithSystemProperty(CapturedOutput output) { void disableWithSystemProperty(CapturedOutput output) {
System.setProperty(ENABLED_PROPERTY, "false"); System.setProperty(ENABLED_PROPERTY, "false");
testInitialize(false); testInitialize(false, new ImplicitlyEnabledRestartApplicationListener());
assertThat(Restarter.getInstance()).hasFieldOrPropertyWithValue("enabled", false); assertThat(Restarter.getInstance()).hasFieldOrPropertyWithValue("enabled", false);
assertThat(output).contains("Restart disabled due to System property"); assertThat(output).contains("Restart disabled due to System property");
} }
@ -90,14 +90,28 @@ class RestartApplicationListenerTests {
@Test @Test
void enableWithSystemProperty(CapturedOutput output) { void enableWithSystemProperty(CapturedOutput output) {
System.setProperty(ENABLED_PROPERTY, "true"); System.setProperty(ENABLED_PROPERTY, "true");
testInitialize(false); testInitialize(false, new ImplicitlyEnabledRestartApplicationListener());
assertThat(Restarter.getInstance()).hasFieldOrPropertyWithValue("enabled", true); assertThat(Restarter.getInstance()).hasFieldOrPropertyWithValue("enabled", true);
assertThat(output).contains("Restart enabled irrespective of application packaging due to System property"); assertThat(output).contains("Restart enabled irrespective of application packaging due to System property");
} }
private void testInitialize(boolean failed) { @Test
void enableWithSystemPropertyWhenImplicitlyDisabled(CapturedOutput output) {
System.setProperty(ENABLED_PROPERTY, "true");
testInitialize(false, new RestartApplicationListener());
assertThat(Restarter.getInstance()).hasFieldOrPropertyWithValue("enabled", true);
assertThat(output).contains("Restart enabled irrespective of application packaging due to System property");
}
@Test
void implicitlyDisabledInTests(CapturedOutput output) {
testInitialize(false, new RestartApplicationListener());
assertThat(Restarter.getInstance()).hasFieldOrPropertyWithValue("enabled", false);
assertThat(output).contains("Restart disabled due to context in which it is running");
}
private void testInitialize(boolean failed, RestartApplicationListener listener) {
Restarter.clearInstance(); Restarter.clearInstance();
RestartApplicationListener listener = new RestartApplicationListener();
DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext(); DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
SpringApplication application = new SpringApplication(); SpringApplication application = new SpringApplication();
ConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class); ConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class);
@ -113,4 +127,13 @@ class RestartApplicationListenerTests {
} }
} }
private static class ImplicitlyEnabledRestartApplicationListener extends RestartApplicationListener {
@Override
boolean implicitlyEnableRestart() {
return true;
}
}
} }

View File

@ -24,6 +24,7 @@ import java.util.Collections;
import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.awaitility.Awaitility; import org.awaitility.Awaitility;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
@ -37,6 +38,7 @@ import org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles;
import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension; import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.event.ContextClosedEvent; import org.springframework.context.event.ContextClosedEvent;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
@ -44,6 +46,7 @@ import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import static org.assertj.core.api.Assertions.as;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException; import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
@ -90,6 +93,14 @@ class RestarterTests {
}); });
} }
@Test
void testDisabled() {
Restarter.disable();
ConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class);
Restarter.getInstance().prepare(context);
assertThat(Restarter.getInstance()).extracting("rootContexts", as(InstanceOfAssertFactories.LIST)).isEmpty();
}
@Test @Test
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
void getOrAddAttributeWithNewAttribute() { void getOrAddAttributeWithNewAttribute() {