嘎里三分熟
  • 首页
  • JMusic
  • TSBay
  • 常用工具
  • About Me
  • 留言板
一行代码一世浮生
  1. 首页
  2. Java web
  3. SpringBoot
  4. 正文

Spring Boot 全局异常处理(下)

2019年07月23日 2066点热度 2人点赞 0条评论

一、背景

在上篇【链接】中介绍了 Spring Boot 全局异常处理的一种方式,但那是一种全局性的容错机制,目的是把 Spring Boot 默认的 ErrorController 替换掉,从而更友好地展示自定义的异常信息给客户端。

当然,除了这种全局的容错机制,有时候我们更希望对 Controller 层指定的异常进行特殊的处理,更甚至说这是异常处理的一种标准手段,即业务层的异常直接向上抛即可,不用自己处理,然后由 Controller 层进行统一的异常处理。

说明:本文的全局异常处理,同样可以抽象地理解成:全局处理 Controller 层抛出的异常

二、实现

Spring 给我们提供的两种实现的方式:

  • 局部异常处理:@Controller + @ExceptionHandler
  • 全局异常处理:@ControllerAdvice + @ExceptionHandler

此处的局部和全局的区别在于:

当代理方法出现在 @Controller 注解的类中时,则此方法会代理此 Controller 中的异常。

当代理方法出现在 @ControllerAdvice 注解的类中时,则此方法会代理所有 Controller 中的异常。

三、局部异常处理

局部异常处理,我们只需要在 @Controller 注解的类中写一个自定义的异常处理方法,然后给这个方法添加 @ExceptionHandler 注解即可,效果就是当此类中的方法有未捕获的异常抛出时,异常会以参数的形式传递给这个异常处理方法,我们只需要在此方法中进行相关的异常处理即可。

//局部异常处理(ps:对于参数必填的400异常也会被此异常处理器捕获)
@ExceptionHandler(Exception.class)
public String exHandler(Exception e) {    
    if(e instanceof ArithmeticException) {        
        return "除0异常-局部捕获";    
    }    
    if(e instanceof STCRException) {        
        return "自定义异常-局部捕获";   
    }    
    // 未知的异常做出响应   
    return "未知异常-局部捕获";
}

上述方法会处理所有的异常(因为参数是 Exception),当然,我们也可以根据异常的不同,来编写多个方法分别处理对应的异常(实现的过程只需要参数传递不同的异常类型即可)。

但是我们不可能在所有的类中都写一遍异常的处理方法,所以此处有两个思路:

  • 思路一:抽取异常处理代码做成基类,然后由每个需要异常处理的 Controller 类去继承
    缺点:类的继承机制,其实是一种概念上的属性的继承,此处仅仅是为了获得一个公共方法而去做异常类的继承,显然破坏了代码的优雅性。再言之,类是只能继承一次的,这样做有可能会破坏代码结构的设计。
  • 思路二:抽取代码做成接口,然后由每个需要异常处理的 Controller 类去实现这个接口即可
    这种思路得益于 Java8 的 Functional Interface,即可用在接口中写一个默认方法,此方法中是可以写具体的实现的。
    缺点:对环境的要求有些苛刻,即要求 JDK 的版本至少为 1.8,在某些应用中,显然是不合适的。

最后,无论是哪种抽取基类的实现,都是存在局限性的,因为这都要求我们去继承或实现该基类,显然这不是我们想要的,我们想要的是那种一劳永逸的实现方式。

四、全局异常处理

全局异常处理,其实很简单,我们只需要写一个配置类,在该类上添加注解 @ControllerAdvice,然后在该类中异常处理方法即可,同上文的局部异常处理方法。

效果是该类中的异常处理方法会自动处理所有 Controller 中抛出的异常,这才是满足我们需求的异常处理方式。

@ControllerAdvice
public class GlobalExceptionHandler {    

    //处理自定义的异常    
    @ExceptionHandler(STCRException.class)    
    @ResponseBody    
    public Object customHandler(STCRException e) {        
        return "自定义异常-全局";    
    }    
    
    //其他未处理的异常    
    @ExceptionHandler(Exception.class)    
    @ResponseBody    
    public Object exceptionHandler(Exception e) {        
        return "其它异常-全局";   
        }
}

五、总结

好了,我们先整理一下异常的处理流程,最外层的异常处理由 Spring 的全局异常 ErrorController 来接管,这其实是在过滤器层面进行的异常处理,内层由 @ExceptionHandler 处理所有 Controller 抛出的异常。

比如 404 异常,尚未进入 Controller 层,所以异常由 ErrorController 捕获处理。

比如 必填的参数缺失(400)异常,因为已经进入了 Controller 层,所有异常由 ExceptionHandler 捕获处理。

注:局部异常的优先级是高于全局异常的

image
本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: java SpringBoot 全局异常处理
最后更新:2019年07月23日

GoldenJet

爱折腾技术的90后漫威小死忠程序员一枚

点赞
< 上一篇

文章评论

取消回复

通过电子邮件订阅博客

分类目录
  • BootStrap (2)
  • Bug集中营 (6)
  • Java web (3)
  • JavaScript (7)
  • Java基础 (17)
  • Java工具 (5)
  • Linux (3)
  • Python (3)
  • SpringBoot (14)
  • Spring基础 (8)
  • thymeleaf (1)
  • 娱乐 (3)
  • 小谈 (2)
  • 常用工具 (7)
  • 技术分析集 (5)
  • 技能 (10)
  • 源码 (4)
  • 科普类 (1)
  • 算法 (9)
  • 踩坑记 (5)
文章归档
  • 2020年11月 (1)
  • 2020年7月 (1)
  • 2020年4月 (2)
  • 2020年3月 (1)
  • 2020年1月 (1)
  • 2019年11月 (1)
  • 2019年10月 (1)
  • 2019年9月 (1)
  • 2019年8月 (1)
  • 2019年7月 (2)
  • 2019年5月 (2)
  • 2019年4月 (2)
  • 2019年3月 (3)
  • 2019年2月 (2)
  • 2019年1月 (2)
  • 2018年12月 (2)
  • 2018年11月 (3)
  • 2018年10月 (3)
  • 2018年9月 (2)
  • 2018年8月 (3)
  • 2018年7月 (2)
  • 2018年5月 (1)
  • 2018年4月 (3)
  • 2018年3月 (2)
  • 2018年2月 (3)
  • 2018年1月 (5)
  • 2017年12月 (2)
  • 2017年11月 (3)
  • 2017年10月 (1)
  • 2017年9月 (1)
  • 2017年8月 (1)
  • 2017年7月 (7)
  • 2017年6月 (5)
  • 2017年5月 (1)
  • 2017年4月 (2)
  • 2017年3月 (4)
  • 2017年2月 (2)
小伙伴友链
  • 前端驿站

COPYRIGHT © 2017-2020 嘎里三分熟. ALL RIGHTS RESERVED.

浙ICP备17005575号-1

浙公网安备 33010802009043号