Merge branch '3.2.x'

Closes gh-40451
This commit is contained in:
Andy Wilkinson 2024-04-19 17:31:09 +01:00
commit 3725d70b1d
2 changed files with 59 additions and 1 deletions

View File

@ -80,6 +80,7 @@ import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.NativeDetector;
import org.springframework.core.OrderComparator;
import org.springframework.core.OrderComparator.OrderSourceProvider;
import org.springframework.core.Ordered;
@ -848,7 +849,16 @@ public class SpringApplication {
// Continue with normal handling of the original failure
}
if (logger.isErrorEnabled()) {
logger.error("Application run failed", failure);
if (NativeDetector.inNativeImage()) {
// Depending on how early the failure was, logging may not work in a
// native image so we output the stack trace directly to System.out
// instead.
System.out.println("Application run failed");
failure.printStackTrace(System.out);
}
else {
logger.error("Application run failed", failure);
}
registerLoggedException(failure);
}
}

View File

@ -73,6 +73,7 @@ import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.boot.context.event.ApplicationStartingEvent;
import org.springframework.boot.context.event.SpringApplicationEvent;
import org.springframework.boot.convert.ApplicationConversionService;
import org.springframework.boot.testsupport.classpath.ForkedClassPath;
import org.springframework.boot.testsupport.system.CapturedOutput;
import org.springframework.boot.testsupport.system.OutputCaptureExtension;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
@ -753,6 +754,53 @@ class SpringApplicationTests {
assertThat(output).contains("Application run failed");
}
@Test
void failureOnTheJvmLogsApplicationRunFailed(CapturedOutput output) {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
ExitCodeListener exitCodeListener = new ExitCodeListener();
application.addListeners(exitCodeListener);
@SuppressWarnings("unchecked")
ApplicationListener<SpringApplicationEvent> listener = mock(ApplicationListener.class);
application.addListeners(listener);
ExitStatusException failure = new ExitStatusException();
willThrow(failure).given(listener).onApplicationEvent(isA(ApplicationReadyEvent.class));
assertThatExceptionOfType(RuntimeException.class).isThrownBy(application::run);
then(listener).should().onApplicationEvent(isA(ApplicationReadyEvent.class));
then(listener).should(never()).onApplicationEvent(isA(ApplicationFailedEvent.class));
assertThat(exitCodeListener.getExitCode()).isEqualTo(11);
// Leading space only happens when logging
assertThat(output).contains(" Application run failed").contains("ExitStatusException");
}
@Test
@ForkedClassPath
void failureInANativeImageWritesFailureToSystemOut(CapturedOutput output) {
System.setProperty("org.graalvm.nativeimage.imagecode", "true");
try {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
ExitCodeListener exitCodeListener = new ExitCodeListener();
application.addListeners(exitCodeListener);
@SuppressWarnings("unchecked")
ApplicationListener<SpringApplicationEvent> listener = mock(ApplicationListener.class);
application.addListeners(listener);
ExitStatusException failure = new ExitStatusException();
willThrow(failure).given(listener).onApplicationEvent(isA(ApplicationReadyEvent.class));
assertThatExceptionOfType(RuntimeException.class).isThrownBy(application::run);
then(listener).should().onApplicationEvent(isA(ApplicationReadyEvent.class));
then(listener).should(never()).onApplicationEvent(isA(ApplicationFailedEvent.class));
assertThat(exitCodeListener.getExitCode()).isEqualTo(11);
// Leading space only happens when logging
assertThat(output).doesNotContain(" Application run failed")
.contains("Application run failed")
.contains("ExitStatusException");
}
finally {
System.clearProperty("org.graalvm.nativeimage.imagecode");
}
}
@Test
void loadSources() {
Class<?>[] sources = { ExampleConfig.class, TestCommandLineRunner.class };