千家信息网

[SpringBoot]源码分析SpringBoot的异常处理机制

发表于:2025-01-24 作者:千家信息网编辑
千家信息网最后更新 2025年01月24日,微信号:GitShare微信公众号:爱折腾的稻草如有问题或建议,请在公众号留言[1]前续为帮助广大SpringBoot用户达到"知其然,更需知其所以然"的境界,作者将通过SpringBoot系列文章全
千家信息网最后更新 2025年01月24日[SpringBoot]源码分析SpringBoot的异常处理机制

微信号:GitShare
微信公众号:爱折腾的稻草
如有问题或建议,请在公众号留言[1]

前续

为帮助广大SpringBoot用户达到"知其然,更需知其所以然"的境界,作者将通过SpringBoot系列文章全方位对SpringBoot2.0.0.RELEASE版本深入分解剖析,让您深刻的理解其内部工作原理。

正文

在SpringBoot启动时,会查找并加载所有可用的SpringBootExceptionReporter,其源码如下:

//7 使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的SpringBootExceptionReporter
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);

继续查看getSpringFactoriesInstances方法源码:

private  Collection getSpringFactoriesInstances(Class type,
Class[] parameterTypes, Object... args)
{
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
//查找并加载classpath路径下META-INF/spring.factories中配置的SpringBootExceptionReporter的所有名称
Set names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//实例化所有的SpringBootExceptionReporter
List instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
//排序
AnnotationAwareOrderComparator.sort(instances);
//返回结果
return instances;
}

代码来看不难,也是通过Spring的Factories机制来加载,之前的文章中已经详细讲解过其过程。

SpringBootExceptionReporter
@FunctionalInterface
public interface SpringBootExceptionReporter
{

/**
* 向用户报告启动失败。
*/

boolean reportException(Throwable failure);

}
  • SpringBootExceptionReporter是一个回调接口,用于支持对SpringApplication启动错误的自定义报告。
    里面就一个报告启动失败的方法。

  • 其实现类:org.springframework.boot.diagnostics.FailureAnalyzers
    用于触发从spring.factories加载的FailureAnalyzer和FailureAnalysisReporter实例。

FailureAnalyzers
1、实例化FailureAnalyzers
FailureAnalyzers(ConfigurableApplicationContext context) {
this(context, null);
}

FailureAnalyzers(ConfigurableApplicationContext context, ClassLoader classLoader) {
Assert.notNull(context, "Context must not be null");
this.classLoader = (classLoader == null ? context.getClassLoader() : classLoader);
this.analyzers = loadFailureAnalyzers(this.classLoader);
prepareFailureAnalyzers(this.analyzers, context);
}
  • 获取类加载器

  • 加载并实例化所有的FailureAnalyzer
    通过Spring的Factories机制来查找和加载所有的FailureAnalyzer,
    加载/META/spring.factories 中的org.springframework.boot.diagnostics.FailureAnalyzer配置如下:

# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer
  • 准备所有的FailureAnalyzer

private void prepareAnalyzer(ConfigurableApplicationContext context,
FailureAnalyzer analyzer)
{
if (analyzer instanceof BeanFactoryAware) {
((BeanFactoryAware) analyzer).setBeanFactory(context.getBeanFactory());
}
if (analyzer instanceof EnvironmentAware) {
((EnvironmentAware) analyzer).setEnvironment(context.getEnvironment());
}
}

准备阶段:根据FailureAnalyzer的类型,设置其BeanFactory或者Environment属性值。

2、FailureAnalyzer
@FunctionalInterface
public interface FailureAnalyzer
{

/**
* 返回给定故障的分析,如果不无法分析,则返回null。
*/

FailureAnalysis analyze(Throwable failure);

}

用于分析故障并提供可以显示给用户的诊断信息。

3、AbstractFailureAnalyzer

FailureAnalyzer的抽象基类,是个泛型类,泛型参数为Throwable的子类.其实现了analyze方法,源码如下:

@Override
public FailureAnalysis analyze(Throwable failure)
{
// 1. 获得failure中的异常堆栈中是type类型的异常
T cause = findCause(failure, getCauseType());
if (cause != null) {
// 2. 如果不等于null,则进行分析
return analyze(failure, cause);
}
// 3. 无法分析,则返回null
return null;
}
  • 获得failure中的异常堆栈中是type类型的异常。

protected final  E findCause(Throwable failure, Class type) {
while (failure != null) {
if (type.isInstance(failure)) {
return (E) failure;
}
failure = failure.getCause();
}
return null;
}
  • AbstractFailureAnalyzer的具体实现

3.1、AbstractInjectionFailureAnalyzer:用来对注入异常进行分析的抽象基类。    
3.2、BeanCurrentlyInCreationFailureAnalyzer:针对BeanCurrentlyInCreationException.对BeanCurrentlyInCreationException(循环依赖)进行分析。
3.3、BeanNotOfRequiredTypeFailureAnalyzer:针对BeanNotOfRequiredTypeException异常进行分析。
3.4、BindFailureAnalyzer:针对BindException异常进行分析。
3.5、BindValidationFailureAnalyzer :针对BindValidationException或者BindException异常进行分析。
3.6、ConnectorStartFailureAnalyzer:针对ConnectorStartFailedException(tomcat端口占用时抛出)异常进行分析。
3.7、DataSourceBeanCreationFailureAnalyzer:针对DataSourceBeanCreationException异常进行分析。
3.8、HikariDriverConfigurationFailureAnalyzer:它对使用不支持的"dataSourceClassName"属性导致的Hikari配置失败进行分析。
3.9、InvalidConfigurationPropertyNameFailureAnalyzer:针对InvalidConfigurationPropertyNameException异常进行分析。
3.10、InvalidConfigurationPropertyValueFailureAnalyzer:针对InvalidConfigurationPropertyValueException异常进行分析。
3.11、NoUniqueBeanDefinitionFailureAnalyzer:针对NoUniqueBeanDefinitionException异常进行分析,且实现了BeanFactoryAware接口。
3.12、PortInUseFailureAnalyzer:针对PortInUseException(jetty,undertow 容器启动时端口占用时抛出)异常进行分析。
3.13、UnboundConfigurationPropertyFailureAnalyzer:针对BindException异常进行分析。
3.14、ValidationExceptionFailureAnalyzer:泛型参数为ValidationException(当使用validation相关的注解,但是没有加入相关实现时触发,一般不容易触发,因为一旦加入spring-boot-starter-web依赖,就会加入hibernate-validator)。
4、失败报告(FailureAnalysisReporter)
@FunctionalInterface
public interface FailureAnalysisReporter
{

/**
* 将失败结果(failureAnalysis)报告给用户
*/

void report(FailureAnalysis analysis);

}
  • 失败结果报告接口,将失败结果信息报告给用户

  • 其实现类:LoggingFailureAnalysisReporter

public final class LoggingFailureAnalysisReporter implements FailureAnalysisReporter {

private static final Log logger = LogFactory
.getLog(LoggingFailureAnalysisReporter.class);

@Override
public void report(FailureAnalysis failureAnalysis) {
if (logger.isDebugEnabled()) {
logger.debug("Application failed to start due to an exception",
failureAnalysis.getCause());
}
if (logger.isErrorEnabled()) {
logger.error(buildMessage(failureAnalysis));
}
}

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();
}

}

通过日志的方式进行打印失败错误信息。

小结

Spring的代码使用了很多设计模式,所以阅读起来总是绕来绕去,个人感觉其可读性比较差。今天原本是想画出异常处理机制的相关类图,但是发现这里的接口和类的关系都比较简单,所以就偷懒。如果您通过本文讲解,还不是很清晰的话,您可以将其类图画出来,那样会帮助您理解。

后记

为帮助广大SpringBoot用户达到"知其然,更需知其所以然"的境界,作者将通过SpringBoot系列文章全方位对SpringBoot2.0.0.RELEASE版本深入分解剖析,让您深刻的理解其内部工作原理。

本系列历史文章列表
  • 1、[SpringBoot]利用SpringBoot快速构建并启动项目

  • 2、[SpringBoot]详解SpringBoot应用的启动过程

  • 3、[SpringBoot]深入浅出剖析SpringBoot的应用类型识别机制

  • 4、[SpringBoot]深入浅出剖析SpringBoot中Spring Factories机制

  • 5、[SpringBoot]详解SpringBoot中SpringApplication的run方法的前三步

  • 6、[SpringBoot]图解Spring的Environment机制

  • 7、[SpringBoot]源码解析SpringBoot应用Environment的构造过程

  • 8、[SpringBoot]源码解析SpringBoot的Banner机制

  • 9、[SpringBoot]图解SpringBoot的应用上下文机制




分析 机制 报告 用户 源码 应用 实例 接口 文章 方法 类型 结果 剖析 信息 过程 配置 深入浅出 知其所以然 知其然 代码 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 大学生网络安全对联 思科路由器是服务器吗 宁波第二届网络安全大赛 安卓软件开发设计简单的选题 鹰潭高性价比服务器哪里比较好 mysql在线数据库管理 网络软件开发书籍 昌平区品牌软件开发价格走势 网页设计修改密码代码数据库 汽车上采用的网络技术有哪些优点 桌面共享软件开发的优势有哪些 药品广告数据库驴胶补血颗粒 大学生创业网络技术培训 阿里云日本服务器 网络安全需要下载的软件 2021网络安全教育观后感 ipv6访问阿里云服务器 计算机网络技术是网络安全吗 北京小型软件开发服务放心可靠 禅城企业网络安全产品 家庭教育和网络安全教育平台 会计网络技术有前途吗 网络技术教学基础 戴尔服务器配置管理 林哥网络技术工作室 崩坏三服务器购买 erp开票属于数据库软件吗 桌面共享软件开发的优势有哪些 南京通信网络技术服务价格 计算机的网络技术说课稿模板
0