当前位置:首页 > 公众号精选 > 架构师社区
[导读]目录前言SpringBoot版本全局统一异常处理的前世今生SpringBoot的异常如何分类?如何统一异常处理?异常匹配的顺序是什么?总结前言软件开发过程中难免遇到各种的BUG,各种的异常,一直就是在解决异常的路上永不停歇,如果你的代码中再出现try(){...}catch(){...

目录

  • 前言
  • Spring Boot 版本
  • 全局统一异常处理的前世今生
  • Spring Boot的异常如何分类?
  • 如何统一异常处理?
  • 异常匹配的顺序是什么?
  • 总结

前言

软件开发过程中难免遇到各种的BUG,各种的异常,一直就是在解决异常的路上永不停歇,如果你的代码中再出现try(){...}catch(){...}finally{...}代码块,你还有心情看下去吗?自己不觉得恶心吗?

冗余的代码往往回丧失写代码的动力,每天搬砖似的写代码,真的很难受。今天这篇文章教你如何去掉满屏的try(){...}catch(){...}finally{...},解放你的双手。

Spring Boot 版本

本文基于的Spring Boot的版本是2.3.4.RELEASE

全局统一异常处理的前世今生

早在Spring 3.x就已经提出了@ControllerAdvice,可以与@ExceptionHandler@InitBinder@ModelAttribute 等注解注解配套使用,这几个此处就不再详细解释了。

这几个注解小眼一瞟只有@ExceptionHandler与异常有关啊,翻译过来就是异常处理器其实异常的处理可以分为两类,分别是局部异常处理全局异常处理

局部异常处理@ExceptionHandler@Controller注解搭配使用,只有指定的controller层出现了异常才会被@ExceptionHandler捕获到,实际生产中怕是有成百上千个controller了吧,显然这种方式不合适。

全局异常处理:既然局部异常处理不合适了,自然有人站出来解决问题了,于是就有了@ControllerAdvice这个注解的横空出世了,@ControllerAdvice搭配@ExceptionHandler彻底解决了全局统一异常处理。当然后面还出现了@RestControllerAdvice这个注解,其实就是@ControllerAdvice@ResponseBody结晶。

Spring Boot的异常如何分类?

Java中的异常就很多,更别说Spring Boot中的异常了,这里不再根据传统意义上Java的异常进行分类了,而是按照controller进行分类,分为进入controller前的异常业务层的异常,如下图:

满屏的try-catch,你不瘆得慌?
进入controller之前异常一般是javax.servlet.ServletException类型的异常,因此在全局异常处理的时候需要统一处理。几个常见的异常如下:

  1. NoHandlerFoundException:客户端的请求没有找到对应的controller,将会抛出404异常。
  2. HttpRequestMethodNotSupportedException:若匹配到了(匹配结果是一个列表,不同的是http方法不同,如:Get、Post等),则尝试将请求的http方法与列表的控制器做匹配,若没有对应http方法的控制器,则抛该异常
  3. HttpMediaTypeNotSupportedException:然后再对请求头与控制器支持的做比较,比如content-type请求头,若控制器的参数签名包含注解@RequestBody,但是请求的content-type请求头的值没有包含application/json,那么会抛该异常(当然,不止这种情况会抛这个异常)
  4. MissingPathVariableException:未检测到路径参数。比如url为:/user/{userId},参数签名包含@PathVariable("userId"),当请求的url为/user,在没有明确定义url为/user的情况下,会被判定为:缺少路径参数

如何统一异常处理?

在统一异常处理之前其实还有许多东西需要优化的,比如统一结果返回的形式。当然这里不再细说了,不属于本文范畴。

统一异常处理很简单,这里以前后端分离的项目为例,步骤如下

  1. 新建一个统一异常处理的一个类
  2. 类上标注@RestControllerAdvice这一个注解,或者同时标注@ControllerAdvice@ResponseBody这两个注解。
  3. 在方法上标注@ExceptionHandler注解,并且指定需要捕获的异常,可以同时捕获多个。
下面是作者随便配置一个demo,如下:

/**
 * 全局统一的异常处理,简单的配置下,根据自己的业务要求详细配置
 */

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {


    /**
     * 重复请求的异常
     * @param ex
     * @return
     */

    @ExceptionHandler(RepeatSubmitException.class)
    public ResultResponse onException(RepeatSubmitException ex){
        //打印日志
        log.error(ex.getMessage());
        //todo 日志入库等等操作

        //统一结果返回
        return new ResultResponse(ResultCodeEnum.CODE_NOT_REPEAT_SUBMIT);
    }


    /**
     * 自定义的业务上的异常
     */

    @ExceptionHandler(ServiceException.class)
    public ResultResponse onException(ServiceException ex){
        //打印日志
        log.error(ex.getMessage());
        //todo 日志入库等等操作

        //统一结果返回
        return new ResultResponse(ResultCodeEnum.CODE_SERVICE_FAIL);
    }


    /**
     * 捕获一些进入controller之前的异常,有些4xx的状态码统一设置为200
     * @param ex
     * @return
     */

    @ExceptionHandler({HttpRequestMethodNotSupportedException.class,
            HttpMediaTypeNotSupportedException.class, HttpMediaTypeNotAcceptableException.class,
            MissingPathVariableException.class, MissingServletRequestParameterException.class,
            ServletRequestBindingException.class, ConversionNotSupportedException.class,
            TypeMismatchException.class, HttpMessageNotReadableException.class,
            HttpMessageNotWritableException.class,
            MissingServletRequestPartException.class, BindException.class,
            NoHandlerFoundException.class, AsyncRequestTimeoutException.class})
    public ResultResponse onException(Exception ex){
        //打印日志
        log.error(ex.getMessage());
        //todo 日志入库等等操作

        //统一结果返回
        return new ResultResponse(ResultCodeEnum.CODE_FAIL);
    }
}
注意上面的只是一个例子,实际开发中还有许多的异常需要捕获,比如TOKEN失效过期等等异常,如果整合了其他的框架,还要注意这些框架抛出的异常,比如ShiroSpring Security等等框架。

异常匹配的顺序是什么?

有些朋友可能疑惑了,如果我同时捕获了父类和子类,那么到底能够被那个异常处理器捕获呢?比如ExceptionServiceException

此时可能就疑惑了,这里先揭晓一下答案,当然是ServiceException的异常处理器捕获了,精确匹配,如果没有ServiceException的异常处理器才会轮到它的父亲父亲没有才会到祖父。总之一句话,精准匹配,找那个关系最近的。

为什么呢?这可不是凭空瞎说的,源码为证,出处org.springframework.web.method.annotation.ExceptionHandlerMethodResolver#getMappedMethod,如下:

@Nullable
 private Method getMappedMethod(Class exceptionType) {
  List> matches = new ArrayList<>();
    //遍历异常处理器中定义的异常类型
  for (Class mappedException : this.mappedMethods.keySet()) {
      //是否是抛出异常的父类,如果是添加到集合中
   if (mappedException.isAssignableFrom(exceptionType)) {    
        //添加到集合中
    matches.add(mappedException);  
   }
  }
    //如果集合不为空,则按照规则进行排序
  if (!matches.isEmpty()) {
   matches.sort(new ExceptionDepthComparator(exceptionType));
      //取第一个
   return this.mappedMethods.get(matches.get(0));
  }
  else {
   return null;
  }
 }
在初次异常处理的时候会执行上述的代码找到最匹配的那个异常处理器方法,后续都是直接从缓存中(一个Map结构,key是异常类型,value是异常处理器方法)。

别着急,上面代码最精华的地方就是对matches进行排序的代码了,我们来看看ExceptionDepthComparator这个比较器的关键代码,如下:

//递归调用,获取深度,depth值越小越精准匹配
private int getDepth(Class declaredException, Class exceptionToMatch, int depth) {
    //如果匹配了,返回
  if (exceptionToMatch.equals(declaredException)) {
   // Found it!
   return depth;
  }
  // 递归结束的条件,最大限度了
  if (exceptionToMatch == Throwable.class) {
   return Integer.MAX_VALUE;
  }
    //继续匹配父类
  return getDepth(declaredException, exceptionToMatch.getSuperclass(), depth   1);
 }
精髓全在这里了,一个递归搞定,计算深度,depth初始值为0。值越小,匹配度越高越精准。

总结

全局异常的文章万万千,能够讲清楚的能有几篇呢?只出最精的文章,做最野的程序员,如果觉得不错的,关注分享走一波,谢谢支持!!!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭