SpringBoot打印详细启动异常信息

SpringBoot在项目启动时如果遇到异常并不能友好的打印出具体的堆栈错误信息,我们只能查看到简单的错误消息,以致于并不能及时解决发生的问题,针对这个问题SpringBoot提供了故障分析仪的概念(failure-analyzer),内部根据不同类型的异常提供了一些实现,我们如果想自定义该怎么去做?

FailureAnalyzer

SpringBoot提供了启动异常分析接口FailureAnalyzer,该接口位于org.springframework.boot.diagnosticspackage内。内部仅提供一个分析的方法,源码如下所示:

@FunctionalInterface
public interface FailureAnalyzer {

    /**
     * Returns an analysis of the given {@code failure}, or {@code null} if no analysis
     * was possible.
     * @param failure the failure
     * @return the analysis or {@code null}
     */
    FailureAnalysis analyze(Throwable failure);

}

该接口会把遇到的异常对象实例Throwable failure交付给实现类,实现类进行自定义处理。

AbstractFailureAnalyzer

AbstractFailureAnalyzer是FailureAnalyzer的基础实现抽象类,实现了FailureAnalyzer定义的analyze(Throwable failure)方法,并提供了一个指定异常类型的抽象方法analyze(Throwable rootFailure, T cause),源码如下所示:

public abstract class AbstractFailureAnalyzer<T extends Throwable> implements FailureAnalyzer {

    @Override
    public FailureAnalysis analyze(Throwable failure) {
        T cause = findCause(failure, getCauseType());
        if (cause != null) {
            return analyze(failure, cause);
        }
        return null;
    }

    /**
     * Returns an analysis of the given {@code rootFailure}, or {@code null} if no
     * analysis was possible.
     * @param rootFailure the root failure passed to the analyzer
     * @param cause the actual found cause
     * @return the analysis or {@code null}
     */
    protected abstract FailureAnalysis analyze(Throwable rootFailure, T cause);

    /**
     * Return the cause type being handled by the analyzer. By default the class generic
     * is used.
     * @return the cause type
     */
    @SuppressWarnings("unchecked")
    protected Class<? extends T> getCauseType() {
        return (Class<? extends T>) ResolvableType.forClass(AbstractFailureAnalyzer.class, getClass()).resolveGeneric();
    }

    @SuppressWarnings("unchecked")
    protected final <E extends Throwable> E findCause(Throwable failure, Class<E> type) {
        while (failure != null) {
            if (type.isInstance(failure)) {
                return (E) failure;
            }
            failure = failure.getCause();
        }
        return null;
    }

}

通过AbstractFailureAnalyzer源码我们可以看到,它在实现于FailureAnalyzer的接口方法内进行了特殊处理,根据getCauseType()方法获取当前类定义的第一个泛型类型,也就是我们需要分析的指定异常类型。

获取泛型异常类型后根据方法findCause判断Throwable是否与泛型异常类型匹配,如果匹配直接返回给SpringBoot进行注册处理。

SpringBoot提供的分析实现

SpringBoot内部通过实现AbstractFailureAnalyzer抽象类定义了一系列的针对性异常类型的启动分析,如下图所示:

指定异常分析

SpringBoot内部提供的启动异常分析都是指定具体的异常类型实现的,最常见的一个错误就是端口号被占用(PortInUseException),虽然SpringBoot内部提供一个这个异常的启动分析,我们也是可以进行替换这一异常分析的,我们只需要创建PortInUseException异常的AbstractFailureAnalyzer,并且实现类注册给SpringBoot即可,实现自定义如下所示:

/**
 * 端口号被占用{@link PortInUseException}异常启动分析
 *
 * @author 恒宇少年
 */
public class PortInUseFailureAnalyzer extends AbstractFailureAnalyzer<PortInUseException> {
    /**
     * logger instance
     */
    static Logger logger = LoggerFactory.getLogger(PortInUseFailureAnalyzer.class);

    @Override
    protected FailureAnalysis analyze(Throwable rootFailure, PortInUseException cause) {
        logger.error("端口被占用。", cause);
        return new FailureAnalysis("端口号:"   cause.getPort()   "被占用", "PortInUseException", rootFailure);
    }
}

注册启动异常分析

在上面我们只是编写了指定异常启动分析,我们接下来需要让它生效,这个生效方式比较特殊,类似于自定义SpringBoot Starter AutoConfiguration的形式,我们需要在META-INF/spring.factories文件内进行定义,如下所示:

org.springframework.boot.diagnostics.FailureAnalyzer=\
  org.minbox.chapter.springboot.failure.analyzer.PortInUseFailureAnalyzer

那我们为什么需要使用这种方式定义呢?

项目启动遇到的异常顺序不能确定,很可能在Spring IOC并未执行初始化之前就出现了异常,我们不能通过@Component注解的形式使其生效,所以SpringBoot提供了通过spring.factories配置文件的方式定义。

启动异常分析继承关系

自定义的运行异常一般都是继承自RuntimeException,如果我们定义一个RuntimeException的异常启动分析实例会是什么效果呢?

/**
 * 项目启动运行时异常{@link RuntimeException}统一启动分析
 *
 * @author 恒宇少年
 */
public class ProjectBootUnifiedFailureAnalyzer extends AbstractFailureAnalyzer<RuntimeException> {
    /**
     * logger instance
     */
    static Logger logger = LoggerFactory.getLogger(ProjectBootUnifiedFailureAnalyzer.class);

    @Override
    protected FailureAnalysis analyze(Throwable rootFailure, RuntimeException cause) {
        logger.error("遇到运行时异常", cause);
        return new FailureAnalysis(cause.getMessage(), "error", rootFailure);
    }
}

将该类也一并注册到spring.factories文件内,如下所示:

org.springframework.boot.diagnostics.FailureAnalyzer=\
  org.minbox.chapter.springboot.failure.analyzer.PortInUseFailureAnalyzer,\
  org.minbox.chapter.springboot.failure.analyzer.ProjectBootUnifiedFailureAnalyzer

运行项目并测试端口号被占用异常我们会发现,并没有执行ProjectBootUnifiedFailureAnalyzer内的analyze方法,而是继续执行了PortInUseFailureAnalyzer类内的方法。

那我们将PortInUseFailureAnalyzer这个启动分析从spring.factories文件内暂时删除掉,再来运行项目我们会发现这时却是会执行ProjectBootUnifiedFailureAnalyzer类内分析方法。

总结

根据本章我们了解了SpringBoot提供的启动异常分析接口以及基本抽象实现类的运作原理,而且启动异常分析存在分析泛型异常类的上下级继承关系,异常子类的启动分析会覆盖掉异常父类的启动分析,如果你想包含全部异常的启动分析可以尝试使用Exception作为AbstractFailureAnalyzer的泛型参数。

到此这篇关于SpringBoot打印详细启动异常信息的文章就介绍到这了,更多相关SpringBoot打印启动异常信息内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • SpringBoot使用@SpringBootTest注解开发单元测试教程

    概述 @SpringBootTest注解是SpringBoot自1.4.0版本开始引入的一个用于测试的注解.基本用法如下: 1.添加依赖: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.

  • 解决try-catch捕获异常信息后Spring事务失效的问题

    一.首先在Spring Boot项目中,手动添加异常方法进行测试 @Transactional(rollbackFor=Exception.class) //表示此方法有异常时触发Spring事务 @Override public CommonResult<User> saveUser(User user) { int insert = baseMapper.insert(user); try { // 添加异常,并进行捕获 int a = 10/0; }catch (Exception e)

  • java捕获异常信息存入txt文件示例

    捕获程序中出现的异常 可用于后期维护的必要性!做简单的测试 ! 复制代码 代码如下: package helpEntity; import java.io.BufferedReader;import java.io.File;import java.io.FileReader;import java.io.FileWriter;import java.io.PrintWriter;import java.text.SimpleDateFormat;import java.util.Date; p

  • SpringBoot如何使用RequestBodyAdvice进行统一参数处理

    SpringBoot RequestBodyAdvice参数处理 在实际项目中 , 往往需要对请求参数做一些统一的操作 , 例如参数的过滤 , 字符的编码 , 第三方的解密等等 , Spring提供了RequestBodyAdvice一个全局的解决方案 , 免去了我们在Controller处理的繁琐 . RequestBodyAdvice仅对使用了@RqestBody注解的生效 , 因为它原理上还是AOP , 所以GET方法是不会操作的. package com.xbz.common.web;

  • Android保存App异常信息到本地

    本文实例为大家分享了Android保存App异常信息到本地的具体代码,供大家参考,具体内容如下 首先添加权限 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 代码 // 调用该方法造成异常 private void math() { try { int a = 0; int b = 10; int c = b / a; } catch (Exception e) { e.

  • SpringBoot2.x 集成腾讯云短信的详细流程

    一.腾讯云短信简介 腾讯云短信(Short Message Service,SMS)沉淀腾讯十多年短信服务技术和经验,为QQ.微信等亿级平台和10万+客户提供快速灵活接入的高质量的国内短信与国际/港澳台短信服务. 国内短信验证秒级触达,99%到达率. 国际/港澳台短信覆盖全球200+国家/地区,稳定可靠. 单次短信的业务请求流程如下所示: 短信由签名和正文内容组成,发送短信前需要申请短信签名和正文内容模板.短信签名是位于短信正文前[]中的署名,用于标识公司或业务.短信签名需要审核通过后才可使用.

  • SpringBoot打印详细启动异常信息

    SpringBoot在项目启动时如果遇到异常并不能友好的打印出具体的堆栈错误信息,我们只能查看到简单的错误消息,以致于并不能及时解决发生的问题,针对这个问题SpringBoot提供了故障分析仪的概念(failure-analyzer),内部根据不同类型的异常提供了一些实现,我们如果想自定义该怎么去做? FailureAnalyzer SpringBoot提供了启动异常分析接口FailureAnalyzer,该接口位于org.springframework.boot.diagnosticspack

  • Python 输出详细的异常信息(traceback)方式

    问题描述 为了程序的正常运行,进行异常处理是有必要的,甚至于有时候,我们会主动的抛出异常,然后让程序进行异常捕获,再进行进一步的处理.但是,在开发的程序相对较大的过程中,我们不能一昧的进行try....except.而是要弄清楚到底抛出的是什么异常,同时,对于某些未知的异常,我们应该清楚的定位到到底是哪一行程序抛出的异常,针对这种情况,traceback库能极大的帮助我们. 解决方法 代码只需一行,即 print(traceback.format_exc()) 即可,这样即可打印详细的信息,这个

  • SpringBoot之自定义启动异常堆栈信息打印方式

    在SpringBoot项目启动过程中,当一些配置或者其他错误信息会有一些的规范的提示信息 *************************** APPLICATION FAILED TO START *************************** Description: Web server failed to start. Port 8080 was already in use. Action: Identify and stop the process that's liste

  • python如何利用traceback获取详细的异常信息

    除了使用 sys.exc_info() 方法获取更多的异常信息之外,还可以使用 traceback 模块,该模块可以用来查看异常的传播轨迹,追踪异常触发的源头. try: 1/0 except Exception,e: print e 输出结果是integer division or modulo by zero,只知道是报了这个错,但是却不知道在哪个文件哪个函数哪一行报的错. 下面使用traceback模块 traceback是python中用来跟踪异常信息的模块,方便把程序中的运行异常打印或

  • SpringBoot打印启动时异常堆栈信息详解

    SpringBoot在项目启动时如果遇到异常并不能友好的打印出具体的堆栈错误信息,我们只能查看到简单的错误消息,以致于并不能及时解决发生的问题,针对这个问题SpringBoot提供了故障分析仪的概念(failure-analyzer),内部根据不同类型的异常提供了一些实现,我们如果想自定义该怎么去做? FailureAnalyzer SpringBoot提供了启动异常分析接口FailureAnalyzer,该接口位于org.springframework.boot.diagnosticspack

  • Python使用sys.exc_info()方法获取异常信息

    在实际调试程序的过程中,有时只获得异常的类型是远远不够的,还需要借助更详细的异常信息才能解决问题. 捕获异常时,有 2 种方式可获得更多的异常信息,分别是: 使用 sys 模块中的 exc_info 方法: 使用 traceback 模块中的相关函数. 本节首先介绍如何使用 sys 模块中的 exc_info() 方法获得更多的异常信息. 有关 sys 模块更详细的介绍,可阅读<Python sys模块>. 模块 sys 中,有两个方法可以返回异常的全部信息,分别是 exc_info() 和

  • python打印异常信息的两种实现方式

    1. 直接打印错误 try: # your code except KeyboardInterrupt: print("quit") except Exception as ex: print("出现如下异常%s"%ex) 如下例子 try: 2/0 except Exception as e: print(e) 结果为:division by zero 2. 用traceback模块打印 上述结果看不到具体错误的信息,如行数啥的,不方便调试的时候定位,因此也可以用

  • SpringBoot WebSocket实时监控异常的详细流程

    目录 写在前面 实现: 前端: 后端: 测试 写在前面 此异常非彼异常,标题所说的异常是业务上的异常. 最近做了一个需求,消防的设备巡检,如果巡检发现异常,通过手机端提交,后台的实时监控页面实时获取到该设备的信息及位置,然后安排员工去处理. 因为需要服务端主动向客户端发送消息,所以很容易的就想到了用WebSocket来实现这一功能. WebSocket就不做介绍了,上链接:https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket 前端略

  • Python中捕捉详细异常信息的代码示例

    大家在开发的过程中可能时常碰到一个需求,需要把Python的异常信息输出到日志文件中. 网上的办法都不太实用,下面介绍一种实用的,从Python 2.7源码中扣出来的. 废话不说 直接上代码,代码不多,注释比较多而已. import sys, traceback traceback_template = '''Traceback (most recent call last): File "%(filename)s", line %(lineno)s, in %(name)s %(ty

  • SpringBoot实战之处理异常案例详解

    前段时间写了一篇关于实现统一响应信息的博文,根据文中实战操作,能够解决正常响应的一致性,但想要实现优雅响应,还需要优雅的处理异常响应,所以有了这篇内容. 作为后台服务,能够正确的处理程序抛出的异常,并返回友好的异常信息是非常重要的,毕竟我们大部分代码都是为了 处理异常情况.而且,统一的异常响应,有助于客户端理解服务端响应,并作出正确处理,而且能够提升接口的服务质量. SpringBoot提供了异常的响应,可以通过/error请求查看效果: 这是从浏览器打开的场景,也就是请求头不包括content

随机推荐