Make context available when handling refresh failure

Previously, if SpringApplication.run failed due to the refresh of the
application context throwing an exception, the application context
would not be available during run failure handling. This meant that
null was passed to any SpringApplicationRunListeners, however the
javadoc for the finished method does not indicate that it is possible
for null to be passed in. In addition to the possibility of a
NullPointerException, a side-effect of this behaviour was that the
auto-configuration report was not produced when refresh fails, making
it useless as a tool for diagnosing refresh failures.

This commit updates SpringApplication to take a reference to the
application context as early as possible and, crucially, before it
has been refreshed. This means that refresh no longer has to succeed for
the context to be passed to any SpringApplicationRunListeners and that
they will now receive an inactive context, rather than a null context in
the event of a refresh failure.

Closes gh-5325
pull/5372/head
Andy Wilkinson 9 years ago
parent 427d3140b3
commit 474aed0541

@ -305,7 +305,14 @@ public class SpringApplication {
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
context = createAndRefreshContext(listeners, applicationArguments);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
if (this.bannerMode != Banner.Mode.OFF) {
printBanner(environment);
}
context = createApplicationContext();
prepareContext(context, environment, listeners, applicationArguments);
refreshContext(context);
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
stopWatch.stop();
@ -321,10 +328,9 @@ public class SpringApplication {
}
}
private ConfigurableApplicationContext createAndRefreshContext(
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
ConfigurableApplicationContext context;
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
@ -332,13 +338,12 @@ public class SpringApplication {
if (isWebEnvironment(environment) && !this.webEnvironment) {
environment = convertToStandardEnvironment(environment);
}
return environment;
}
if (this.bannerMode != Banner.Mode.OFF) {
printBanner(environment);
}
// Create, load, refresh and run the ApplicationContext
context = createApplicationContext();
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
@ -357,8 +362,9 @@ public class SpringApplication {
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
listeners.contextLoaded(context);
}
// Refresh the context
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
@ -368,7 +374,6 @@ public class SpringApplication {
// Not allowed in some environments.
}
}
return context;
}
private void configureHeadlessProperty() {
@ -886,7 +891,7 @@ public class SpringApplication {
private int getExitCodeFromMappedException(ConfigurableApplicationContext context,
Throwable exception) {
if (context == null) {
if (context == null || !context.isActive()) {
return 0;
}
ExitCodeGenerators generators = new ExitCodeGenerators();

@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-2016 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.
@ -62,7 +62,8 @@ public interface SpringApplicationRunListener {
/**
* Called immediately before the run method finishes.
* @param context the application context
* @param context the application context or null if a failure occurred before the
* context was created
* @param exception any run exception or null if run completed successfully.
*/
void finished(ConfigurableApplicationContext context, Throwable exception);

Loading…
Cancel
Save