org.springframework.boot.diagnostics.FailureAnalyzer是springboot框架中的一个接口,用于为应用程序启动失败提供详细的诊断报告。当springboot应用程序无法正常启动时,springboot会尝试查找一个或多个实现了FailureAnalyzer接口的类,以提供关于失败原因的详细信息。
通常,FailureAnalyzer的实现会检查特定的异常或条件,并返回一个FailureAnalyzer对象,该对象包含了对失败的描述、操作建议以及可能的动作链接。
一、FailureAnalyzer故障分析示例:
public class RedisIdentifierFailureAnalyzer extends AbstractFailureAnalyzer<NullPointerException> {
@Override
protected FailureAnalysis analyze(Throwable rootFailure, NullPointerException cause) {
return new FailureAnalysis(cause.getMessage(), "Redis默认数据库标识配置缺失", cause);
}
}
上述实现类定义好后,还需要在META-INF/spring.factories文件中指定故障分析类:
# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.emily.infrastructure.redis.diagnostics.analyzer.RedisIdentifierFailureAnalyzer
首先不配置Redis默认数据库标识,然后运行应用程序,会触发此故障分析类,可以在控制台看到如下信息:
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2024-07-01 20:57:16.194 ERROR default --- [ main] s.b.d.LoggingFailureAnalysisReporter:40 :
***************************
APPLICATION FAILED TO START
***************************
Description:
Redis默认标识不可为空
Action:
Redis默认数据库标识配置缺失
Disconnected from the target VM, address: '127.0.0.1:58630', transport: 'socket'
Process finished with exit code 1
二、故障分析启动流程
- org.springframework.boot.SpringApplication#run(java.lang.String…)方法try…catch…捕获异常调用handleRunFailure方法;
- org.springframework.boot.SpringApplication#handleRunFailure方法调用reportFailure方法;
- org.springframework.boot.SpringApplication#reportFailure方法调用FailureAnalyzers类的reportException方法;
- org.springframework.boot.diagnostics.FailureAnalyzers#reportException方法调用report方法;
- org.springframework.boot.diagnostics.FailureAnalyzers#report方法通过SPI的方式获取spring.factories文件中的故障分析类,并调用org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter#report方法,最终调用buildMessage方法打印故障分析信息。
org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter#buildMessage代码如下:
private String buildMessage(FailureAnalysis failureAnalysis) {
StringBuilder builder = new StringBuilder();
builder.append(String.format("%n%n"));
builder.append(String.format("***************************%n"));
builder.append(String.format("APPLICATION FAILED TO START%n"));
builder.append(String.format("***************************%n%n"));
builder.append(String.format("Description:%n%n"));
builder.append(String.format("%s%n", failureAnalysis.getDescription()));
if (StringUtils.hasText(failureAnalysis.getAction())) {
builder.append(String.format("%nAction:%n%n"));
builder.append(String.format("%s%n", failureAnalysis.getAction()));
}
return builder.toString();
}