栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot源码分析之异常处理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot源码分析之异常处理

微信号:cgmx9880
微信公众号:java 进阶营
如有问题或建议,请在公众号留言[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 {

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 {

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版本深入分解剖析,让您深刻的理解其内部工作原理。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/764298.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号