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
This commit is contained in:
@@ -298,6 +298,7 @@ public class SpringApplication {
|
||||
StopWatch stopWatch = new StopWatch();
|
||||
stopWatch.start();
|
||||
ConfigurableApplicationContext context = null;
|
||||
FailureAnalyzers analyzers = null;
|
||||
configureHeadlessProperty();
|
||||
SpringApplicationRunListeners listeners = getRunListeners(args);
|
||||
listeners.started();
|
||||
@@ -308,6 +309,7 @@ public class SpringApplication {
|
||||
applicationArguments);
|
||||
Banner printedBanner = printBanner(environment);
|
||||
context = createApplicationContext();
|
||||
analyzers = new FailureAnalyzers(context);
|
||||
prepareContext(context, environment, listeners, applicationArguments,
|
||||
printedBanner);
|
||||
refreshContext(context);
|
||||
@@ -321,7 +323,7 @@ public class SpringApplication {
|
||||
return context;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
handleRunFailure(context, listeners, ex);
|
||||
handleRunFailure(context, listeners, analyzers, ex);
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
@@ -803,14 +805,15 @@ public class SpringApplication {
|
||||
}
|
||||
|
||||
private void handleRunFailure(ConfigurableApplicationContext context,
|
||||
SpringApplicationRunListeners listeners, Throwable exception) {
|
||||
SpringApplicationRunListeners listeners, FailureAnalyzers analyzers,
|
||||
Throwable exception) {
|
||||
try {
|
||||
try {
|
||||
handleExitCode(context, exception);
|
||||
listeners.finished(context, exception);
|
||||
}
|
||||
finally {
|
||||
reportFailure(exception, context);
|
||||
reportFailure(analyzers, exception);
|
||||
if (context != null) {
|
||||
context.close();
|
||||
}
|
||||
@@ -822,11 +825,9 @@ public class SpringApplication {
|
||||
ReflectionUtils.rethrowRuntimeException(exception);
|
||||
}
|
||||
|
||||
private void reportFailure(Throwable failure,
|
||||
ConfigurableApplicationContext context) {
|
||||
private void reportFailure(FailureAnalyzers analyzers, Throwable failure) {
|
||||
try {
|
||||
if (FailureAnalyzers.analyzeAndReport(failure, getClass().getClassLoader(),
|
||||
context)) {
|
||||
if (analyzers != null && analyzers.analyzeAndReport(failure)) {
|
||||
registerLoggedException(failure);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -42,22 +42,50 @@ import org.springframework.util.ReflectionUtils;
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public final class FailureAnalyzers {
|
||||
|
||||
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,
|
||||
ConfigurableApplicationContext context) {
|
||||
List<FailureAnalyzer> analyzers = loadFailureAnalyzers(classLoader);
|
||||
List<FailureAnalysisReporter> reporters = SpringFactoriesLoader
|
||||
.loadFactories(FailureAnalysisReporter.class, classLoader);
|
||||
FailureAnalysis analysis = analyze(failure, analyzers, context);
|
||||
return report(analysis, reporters);
|
||||
prepareFailureAnalyzers(analyzers, context);
|
||||
FailureAnalysis analysis = analyze(failure, analyzers);
|
||||
return report(analysis, classLoader);
|
||||
}
|
||||
|
||||
private static List<FailureAnalyzer> loadFailureAnalyzers(ClassLoader classLoader) {
|
||||
@@ -79,10 +107,16 @@ public final class FailureAnalyzers {
|
||||
return analyzers;
|
||||
}
|
||||
|
||||
private static FailureAnalysis analyze(Throwable failure,
|
||||
List<FailureAnalyzer> analyzers, ConfigurableApplicationContext context) {
|
||||
private static void prepareFailureAnalyzers(List<FailureAnalyzer> analyzers,
|
||||
ConfigurableApplicationContext context) {
|
||||
for (FailureAnalyzer analyzer : analyzers) {
|
||||
prepareAnalyzer(context, analyzer);
|
||||
}
|
||||
}
|
||||
|
||||
private static FailureAnalysis analyze(Throwable failure,
|
||||
List<FailureAnalyzer> analyzers) {
|
||||
for (FailureAnalyzer analyzer : analyzers) {
|
||||
FailureAnalysis analysis = analyzer.analyze(failure);
|
||||
if (analysis != null) {
|
||||
return analysis;
|
||||
@@ -99,7 +133,9 @@ public final class FailureAnalyzers {
|
||||
}
|
||||
|
||||
private static boolean report(FailureAnalysis analysis,
|
||||
List<FailureAnalysisReporter> reporters) {
|
||||
ClassLoader classLoader) {
|
||||
List<FailureAnalysisReporter> reporters = SpringFactoriesLoader
|
||||
.loadFactories(FailureAnalysisReporter.class, classLoader);
|
||||
if (analysis == null || reporters.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -70,8 +70,7 @@ public class FailureAnalyzersTests {
|
||||
|
||||
private void analyzeAndReport(final String factoriesName, Throwable failure) {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
|
||||
FailureAnalyzers.analyzeAndReport(failure,
|
||||
context.setClassLoader(
|
||||
new ClassLoader(getClass().getClassLoader()) {
|
||||
|
||||
@Override
|
||||
@@ -85,7 +84,8 @@ public class FailureAnalyzersTests {
|
||||
}
|
||||
}
|
||||
|
||||
}, context);
|
||||
});
|
||||
new FailureAnalyzers(context).analyzeAndReport(failure);
|
||||
}
|
||||
|
||||
static class BasicFailureAnalyzer implements FailureAnalyzer {
|
||||
|
||||
Reference in New Issue
Block a user