• SpringBoot RestControllerAdvice异常处理适配原理


             在项目中我们经常通过RestControllerAdvice+ExceptionHandler一起来实现全局的异常处理。

            以下是示例代码

         

    1. package com.xulu.monitor.test;
    2. import org.springframework.web.bind.annotation.ExceptionHandler;
    3. import org.springframework.web.bind.annotation.RestControllerAdvice;
    4. @RestControllerAdvice
    5. public class GlobalExceptionHandler {
    6. @ExceptionHandler(ParentException.class)
    7. public Response handlerChildrenException(){
    8. Response res = new Response();
    9. System.out.println("1111");
    10. return res;
    11. }
    12. @ExceptionHandler(ChildrenException.class)
    13. public Response handlerParentException(){
    14. Response res = new Response();
    15. System.out.println("2222");
    16. return res;
    17. }
    18. @ExceptionHandler(Throwable.class)
    19. public Response handlerThrowable(){
    20. Response res = new Response();
    21. System.out.println("3333");
    22. return res;
    23. }
    24. }
    1. package com.xulu.monitor.test;
    2. public class ChildrenException extends ParentException{
    3. }
    1. package com.xulu.monitor.test;
    2. public class ParentException extends RuntimeException{
    3. }

     在GlobalExceptionHandler我们看到异常处理器会处理ParentException、ChildrenException、Throwable这种异常。其中ChildrenException继承于ParentException,而ParentException继承了

    RuntimeException,而RuntimeException的父父类就是Throwable。

           当系统抛出一个ChildrenException时,按照全局的异常处理机制三处异常处理代码都有执行的可能性。那在springboot中是怎么匹配异常处理代码的。在springboot中上面的全局异常处理是在SpringMvc源码中执行的。当请求出现异常时,

    ExceptionHandlerMethodResolver中的resolveMethod方法会获取匹配的异常处理方法。跟踪resolveMethod方法,发现在该类的getMappedMethod方法中找到了匹配的源码。
    1. private Method getMappedMethod(Class<? extends Throwable> exceptionType) {
    2. List<Class<? extends Throwable>> matches = new ArrayList<>();
    3. for (Class<? extends Throwable> mappedException : this.mappedMethods.keySet()) {
    4. if (mappedException.isAssignableFrom(exceptionType)) {
    5. matches.add(mappedException);
    6. }
    7. }
    8. if (!matches.isEmpty()) {
    9. matches.sort(new ExceptionDepthComparator(exceptionType));
    10. return this.mappedMethods.get(matches.get(0));
    11. }
    12. else {
    13. return null;
    14. }
    15. }

    重点关注上面的的代码我们发现是先排序再取第一条数

    matches.sort(new ExceptionDepthComparator(exceptionType));这段代码。在这段代码中针对ExceptionDepthComparator做了排序。

    在上面的排序类中 发现匹配规则是先匹配类型,如果类型不匹配则匹配其父类,一直匹配到深度最浅的父类。如果一直匹配不到则匹配到Throwable。

    所以如果抛出了ChildrenException异常则优先匹配异常处理器里的ChildrenException异常,如果异常处理里没有声明ChildrenException的异常处理,则匹配异常处理器里的ParentException异常处理器,ParentException没有声明再匹配Throwable。

  • 相关阅读:
    大数据-之LibrA数据库系统告警处理(ALM-12054 证书文件失效)
    MySQL每日备份
    Linux container_of() 宏定义
    信息系统项目管理师---第十章 项目沟通管理和项目干系人管理
    (吊打二维表中的搜索问题) LeetCode刷题之二维表中进行搜索的问题
    JavaSE——数字格式化、产生随机数字、生成验证码
    【SA8295P 源码分析】100 - 获取 88Q5152 Switch Port1、Port2 端口的主从模式 / 传输速率 / 链路状态
    壁挂式新风机市场现状及未来发展趋势分析
    python数据类型之间的互相转换
    企业员工人事管理系统(数据库课设)
  • 原文地址:https://blog.csdn.net/xl649138628/article/details/133386402