微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

SpringBootExceptionReporter
@FunctionalInterface
public interface SpringBootExceptionReporter {

    /**
     * 向用户报告启动失败。
     */
    boolean reportException(Throwable failure);

}
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);
}
# 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
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;
}
protected final <E extends Throwable> findCause(Throwable failure, Class<E> type) {
    while (failure != null) {
        if (type.isinstance(failure)) {
            return (E) failure;
        }
        failure = failure.getCause();
    }
    return null;
}
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的应用上下文机制

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐