Close context if an ApplicationReadyEvent listener fails

This commit makes sure that the `ApplicationContext` is closed properly
if an `ApplicationReadyListener` throws an exception.

Closes gh-12549
This commit is contained in:
Stephane Nicoll
2018-03-28 15:53:39 +02:00
parent 8b29823885
commit 1e2eec5bcd
2 changed files with 42 additions and 7 deletions

View File

@@ -335,10 +335,17 @@ public class SpringApplication {
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, listeners, exceptionReporters, ex);
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
listeners.running(context);
return context;
}
@@ -795,13 +802,15 @@ public class SpringApplication {
}
private void handleRunFailure(ConfigurableApplicationContext context,
SpringApplicationRunListeners listeners,
Throwable exception,
Collection<SpringBootExceptionReporter> exceptionReporters,
Throwable exception) {
SpringApplicationRunListeners listeners) {
try {
try {
handleExitCode(context, exception);
listeners.failed(context, exception);
if (listeners != null) {
listeners.failed(context, exception);
}
}
finally {
reportFailure(exceptionReporters, exception);

View File

@@ -707,6 +707,32 @@ public class SpringApplicationTests {
}
}
@Test
public void failureInReadyEventListenerCloseApplicationContext() {
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));
try {
application.run();
fail("Run should have failed with a RuntimeException");
}
catch (RuntimeException ex) {
verify(listener).onApplicationEvent(isA(ApplicationReadyEvent.class));
verify(listener, never())
.onApplicationEvent(isA(ApplicationFailedEvent.class));
assertThat(exitCodeListener.getExitCode()).isEqualTo(11);
assertThat(this.output.toString()).contains("Application run failed");
}
}
@Test
public void loadSources() {
Class<?>[] sources = { ExampleConfig.class, TestCommandLineRunner.class };
@@ -1427,14 +1453,14 @@ public class SpringApplicationTests {
private static class ExitCodeListener implements ApplicationListener<ExitCodeEvent> {
private int exitCode;
private Integer exitCode;
@Override
public void onApplicationEvent(ExitCodeEvent event) {
this.exitCode = event.getExitCode();
}
public int getExitCode() {
public Integer getExitCode() {
return this.exitCode;
}