• 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。

  • 相关阅读:
    JVM:(十二)StringTable
    用numpy生成18种特殊数组
    Django版本选择、Python兼容问题及更新时间(长期更新)
    操作系统-(第一章上)
    2018 年第二十三届全国青少年信息学奥林匹克联赛初赛
    “高级前端开发技术探索路由的使用及Node安装使用“
    腾讯云服务器OpenCloudOS操作系统详细介绍
    武汉理工大学 Python程序设计第六章测验
    java实现获取钉钉的签到记录
    后端进阶知识 MySQL为什么那么快 图文详解 之 flush 链表 与 LRU链表
  • 原文地址:https://blog.csdn.net/xl649138628/article/details/133386402