Commit 25e72fab authored by Stephane Nicoll's avatar Stephane Nicoll

Initialize FailureAnalyzer earlier

This commit changes `FailureAnalyzers` so that the loaded
`FailureAnalyzer` instances are initialized before the context eventually
fails.

Before this commit, the `BeanFactoryAware` callback was processed at a
time where the context has already shutdown. Some implementations need
to access components that are no longer available.

Instead, we now initialize them before the context is refreshed.

Closes gh-6748
parent 07a50bb1
...@@ -298,6 +298,7 @@ public class SpringApplication { ...@@ -298,6 +298,7 @@ public class SpringApplication {
StopWatch stopWatch = new StopWatch(); StopWatch stopWatch = new StopWatch();
stopWatch.start(); stopWatch.start();
ConfigurableApplicationContext context = null; ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty(); configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args); SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.started(); listeners.started();
...@@ -308,6 +309,7 @@ public class SpringApplication { ...@@ -308,6 +309,7 @@ public class SpringApplication {
applicationArguments); applicationArguments);
Banner printedBanner = printBanner(environment); Banner printedBanner = printBanner(environment);
context = createApplicationContext(); context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments, prepareContext(context, environment, listeners, applicationArguments,
printedBanner); printedBanner);
refreshContext(context); refreshContext(context);
...@@ -321,7 +323,7 @@ public class SpringApplication { ...@@ -321,7 +323,7 @@ public class SpringApplication {
return context; return context;
} }
catch (Throwable ex) { catch (Throwable ex) {
handleRunFailure(context, listeners, ex); handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex); throw new IllegalStateException(ex);
} }
} }
...@@ -803,14 +805,15 @@ public class SpringApplication { ...@@ -803,14 +805,15 @@ public class SpringApplication {
} }
private void handleRunFailure(ConfigurableApplicationContext context, private void handleRunFailure(ConfigurableApplicationContext context,
SpringApplicationRunListeners listeners, Throwable exception) { SpringApplicationRunListeners listeners, FailureAnalyzers analyzers,
Throwable exception) {
try { try {
try { try {
handleExitCode(context, exception); handleExitCode(context, exception);
listeners.finished(context, exception); listeners.finished(context, exception);
} }
finally { finally {
reportFailure(exception, context); reportFailure(analyzers, exception);
if (context != null) { if (context != null) {
context.close(); context.close();
} }
...@@ -822,11 +825,9 @@ public class SpringApplication { ...@@ -822,11 +825,9 @@ public class SpringApplication {
ReflectionUtils.rethrowRuntimeException(exception); ReflectionUtils.rethrowRuntimeException(exception);
} }
private void reportFailure(Throwable failure, private void reportFailure(FailureAnalyzers analyzers, Throwable failure) {
ConfigurableApplicationContext context) {
try { try {
if (FailureAnalyzers.analyzeAndReport(failure, getClass().getClassLoader(), if (analyzers != null && analyzers.analyzeAndReport(failure)) {
context)) {
registerLoggedException(failure); registerLoggedException(failure);
return; return;
} }
......
...@@ -42,22 +42,50 @@ import org.springframework.util.ReflectionUtils; ...@@ -42,22 +42,50 @@ import org.springframework.util.ReflectionUtils;
* *
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Phillip Webb * @author Phillip Webb
* @author Stephane Nicoll
* @since 1.4.0 * @since 1.4.0
*/ */
public final class FailureAnalyzers { public final class FailureAnalyzers {
private static final Log log = LogFactory.getLog(FailureAnalyzers.class); private static final Log log = LogFactory.getLog(FailureAnalyzers.class);
private FailureAnalyzers() { private final ClassLoader classLoader;
private final List<FailureAnalyzer> analyzers;
public FailureAnalyzers(ConfigurableApplicationContext context) {
this.classLoader = context.getClassLoader();
this.analyzers = loadFailureAnalyzers(this.classLoader);
prepareFailureAnalyzers(this.analyzers, context);
}
/**
* Analyze and report the specified {@code failure}.
*
* @param failure the failure to analyze
* @return {@code true} if the failure was handled
*/
public boolean analyzeAndReport(Throwable failure) {
FailureAnalysis analysis = analyze(failure, this.analyzers);
return report(analysis, this.classLoader);
} }
/**
* Analyze and report the specified {@code failure}.
*
* @param failure the failure to analyze
* @param classLoader the classloader to use
* @param context the context to use
* @return {@code true} if the failure was handled
* @deprecated in favour of {@link #analyzeAndReport(Throwable)}
*/
@Deprecated
public static boolean analyzeAndReport(Throwable failure, ClassLoader classLoader, public static boolean analyzeAndReport(Throwable failure, ClassLoader classLoader,
ConfigurableApplicationContext context) { ConfigurableApplicationContext context) {
List<FailureAnalyzer> analyzers = loadFailureAnalyzers(classLoader); List<FailureAnalyzer> analyzers = loadFailureAnalyzers(classLoader);
List<FailureAnalysisReporter> reporters = SpringFactoriesLoader prepareFailureAnalyzers(analyzers, context);
.loadFactories(FailureAnalysisReporter.class, classLoader); FailureAnalysis analysis = analyze(failure, analyzers);
FailureAnalysis analysis = analyze(failure, analyzers, context); return report(analysis, classLoader);
return report(analysis, reporters);
} }
private static List<FailureAnalyzer> loadFailureAnalyzers(ClassLoader classLoader) { private static List<FailureAnalyzer> loadFailureAnalyzers(ClassLoader classLoader) {
...@@ -79,10 +107,16 @@ public final class FailureAnalyzers { ...@@ -79,10 +107,16 @@ public final class FailureAnalyzers {
return analyzers; return analyzers;
} }
private static FailureAnalysis analyze(Throwable failure, private static void prepareFailureAnalyzers(List<FailureAnalyzer> analyzers,
List<FailureAnalyzer> analyzers, ConfigurableApplicationContext context) { ConfigurableApplicationContext context) {
for (FailureAnalyzer analyzer : analyzers) { for (FailureAnalyzer analyzer : analyzers) {
prepareAnalyzer(context, analyzer); prepareAnalyzer(context, analyzer);
}
}
private static FailureAnalysis analyze(Throwable failure,
List<FailureAnalyzer> analyzers) {
for (FailureAnalyzer analyzer : analyzers) {
FailureAnalysis analysis = analyzer.analyze(failure); FailureAnalysis analysis = analyzer.analyze(failure);
if (analysis != null) { if (analysis != null) {
return analysis; return analysis;
...@@ -99,7 +133,9 @@ public final class FailureAnalyzers { ...@@ -99,7 +133,9 @@ public final class FailureAnalyzers {
} }
private static boolean report(FailureAnalysis analysis, private static boolean report(FailureAnalysis analysis,
List<FailureAnalysisReporter> reporters) { ClassLoader classLoader) {
List<FailureAnalysisReporter> reporters = SpringFactoriesLoader
.loadFactories(FailureAnalysisReporter.class, classLoader);
if (analysis == null || reporters.isEmpty()) { if (analysis == null || reporters.isEmpty()) {
return false; return false;
} }
......
...@@ -70,8 +70,7 @@ public class FailureAnalyzersTests { ...@@ -70,8 +70,7 @@ public class FailureAnalyzersTests {
private void analyzeAndReport(final String factoriesName, Throwable failure) { private void analyzeAndReport(final String factoriesName, Throwable failure) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.setClassLoader(
FailureAnalyzers.analyzeAndReport(failure,
new ClassLoader(getClass().getClassLoader()) { new ClassLoader(getClass().getClassLoader()) {
@Override @Override
...@@ -85,7 +84,8 @@ public class FailureAnalyzersTests { ...@@ -85,7 +84,8 @@ public class FailureAnalyzersTests {
} }
} }
}, context); });
new FailureAnalyzers(context).analyzeAndReport(failure);
} }
static class BasicFailureAnalyzer implements FailureAnalyzer { static class BasicFailureAnalyzer implements FailureAnalyzer {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment