核心类解析
FailureAnalyzer:用于分析故障并提供可显示给用户的诊断信息 FailureAnalysis。
@FunctionalInterface
public interface FailureAnalyzer {
FailureAnalysis analyze(Throwable failure);
}
FailureAnalysisReporter:用于向用户报告 FailureAnalyzer 的分析结果 FailureAnalysis。
@FunctionalInterface
public interface FailureAnalysisReporter {
void report(FailureAnalysis analysis);
}
SpringBootExceptionReporter:用于自定义报告 SpringApplication 启动异常的回调接口。
@FunctionalInterface
public interface SpringBootExceptionReporter {
boolean reportException(Throwable failure);
}
FailureAnalyzers:用于触发 FailureAnalyzer 和 FailureAnalysisReporter。
final class FailureAnalyzers implements SpringBootExceptionReporter {
@Override
public boolean reportException(Throwable failure) {
// 调用 FailureAnalyzer 的 analyzer 方法,得到 FailureAnalysis
FailureAnalysis analysis = analyze(failure, this.analyzers);
// 调用 FailureAnalysisReporter 的 report 方法,报告分析结果
return report(analysis, this.classLoader);
}
}
异常处理流程解析
SpringBoot 启动异常处理流程的入口在 org.springframework.boot.SpringApplication#run(java.lang.String...)
方法中。
public ConfigurableApplicationContext run(String... args) {
try {
}
catch (Throwable 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);
}
return context;
}
当启动过程中出现异常或调用 SpringApplicationRunListeners 出现异常时会调用 handleRunFailure 方法,完成异常处理流程。
private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception,
Collection<SpringBootExceptionReporter> exceptionReporters, SpringApplicationRunListeners listeners) {
try {
try {
// 处理 exitCode
handleExitCode(context, exception);
if (listeners != null) {
// 发送 ApplicationFailedEvent 事件
listeners.failed(context, exception);
}
}
finally {
// 调用 FailureAnalyzers 的 reportException 方法报告异常
reportFailure(exceptionReporters, exception);
if (context != null) {
// 关闭应用程序上下文
context.close();
}
}
}
catch (Exception ex) {
logger.warn("Unable to close ApplicationContext", ex);
}
// 重新抛出此异常
ReflectionUtils.rethrowRuntimeException(exception);
}
关闭应用程序上下文的逻辑主要有。
public void close() {
synchronized (this.startupShutdownMonitor) {
doClose();
if (this.shutdownHook != null) {
try {
// 移除 ShutdownHooks,因为 doClose 方法已经明确关闭了 context,不需要借助 ShutdownHooks 来完成这些操作
Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
}
catch (IllegalStateException ex) {
}
}
}
}
protected void doClose() {
// 更改应用上下文状态
if (this.active.get() && this.closed.compareAndSet(false, true)) {
// 销毁单例 Bean
destroyBeans();
// 将 context 中的 beanFactory 置空
closeBeanFactory();
// 留给子类实现:WEB 环境下关闭 WEB 容器
onClose();
this.active.set(false);
}
}