成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

詳解SpringBoot接口異常處理機制及源碼分析

開發 前端
如果異常仍然未解決,則為null,以便后續的解析器嘗試,如果異常在最后仍然存在,則允許它向上冒泡到Servlet容器。

環境:Springboot3.0.5

概述

如果在請求映射期間發生異常或從請求處理程序(例如@Controller)拋出異常,DispatcherServlet將委托給HandlerExceptionResolver。

下表列出了可用的HandlerExceptionResolver實現。

HandlerExceptionResolver 實現類:

HandlerExceptionResolver

描述

SimpleMappingExceptionResolver

異常類名和錯誤視圖名之間的映射。用于在瀏覽器應用程序中渲染錯誤頁面。

DefaultHandlerExceptionResolver

解析Spring MVC引發的異常,并將其映射為HTTP狀態碼。

ResponseStatusExceptionResolver

使用@ResponseStatus注解解析異常,并根據注解中的值將異常映射為HTTP狀態碼。

ExceptionHandlerExceptionResolver

通過在@Controller或@ControllerAdvice類中調用由@ExceptionHandler注釋的方法來解決異常。

我們可以聲明多個HandlerExceptionResolver

HandlerExceptionResolver的約定規定它可以返回:

  • 指向錯誤視圖的ModelAndView。
  • 如果異常是在解析器中處理的,則返回空的ModelAndView。
  • 如果異常仍然未解決,則為null,以便后續的解析器嘗試,如果異常在最后仍然存在,則允許它向上冒泡到Servlet容器。

Controller接口調用原理

SpringMVC請求入口通過DispatcherServlet執行大致核心流程如下:

  1. 首先通過HandlerMapping確定目標Handler對象(如果接口是Controller那么這里會是 HandlerMethod)
  2. 通過上一步Handler對象,確定執行真正調用的HandlerAdapter

這里以Controller接口為例,HandlerAdapter對象為RequestMappingHandlerAdapter。

DispatcherServlet

public class DispatcherServlet extends FrameworkServlet {
  protected void doDispatch(...) throws Exception {
    HandlerExecutionChain mappedHandler = null;
    try {
      Exception dispatchException = null;
      // 根據請求確定Handler對象(遍歷所有的HandlerMapping)
      mappedHandler = getHandler(processedRequest);
      // 根據上一步確定的Handler對象,確定HandlerAdapter對象
      HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
      // 真正執行目標方法的調用
      mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    } catch (Exception ex) {
      dispatchException = ex;
    } catch (Throwable err) {
      dispatchException = new ServletException("Handler dispatch failed: " + err, err);
    }
    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
  }
}

RequestMappingHandlerAdapter

public class RequestMappingHandlerAdapter {
  protected ModelAndView handleInternal(...) throws Exception {
    ModelAndView mav;
    mav = invokeHandlerMethod(request, response, handlerMethod);
  }
  protected ModelAndView invokeHandlerMethod(...) throws Exception {
    // ...
    ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
    // ... 對ServletInvocableHandlerMethod進行配置
    invocableMethod.invokeAndHandle(webRequest, mavContainer);
    return getModelAndView(mavContainer, modelFactory, webRequest);
  }
}

ServletInvocableHandlerMethod執行參數解析目標Controller方法調用及返回值的處理。

public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
  public void invokeAndHandle(...) throws Exception {
    // 該方法中會進行請求參數的解析及目標方法的調用
    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
    // ...
    try {
      // 處理返回值
      this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    } catch (Exception ex) {
      throw ex;
    }
  }
}

通過上面的源碼分析,在調用過程中如果發生了異常會將異常直接拋出,在DispatcherServlet中會進行異常的處理。

異常解析原理分析

接著上面的源碼分析,當發生異常后最終會在DispatcherServlet#processDispatchResult方法中進行處理。

public class DispatcherServlet extends FrameworkServlet {
  /*
    * 默認情況下有如下2個異常解析器
    * 1. DefaultErrorAttributes
    * 2. ExceptionHandlerExceptionResolver
    */
  private List<HandlerExceptionResolver> handlerExceptionResolvers;
  private void processDispatchResult(...) {
    if (exception != null) {
      Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
      // 處理異常
      mv = processHandlerException(request, response, handler, exception);
    }
  }
  protected ModelAndView processHandlerException(...) throws Exception {
    ModelAndView exMv = null;
    if (this.handlerExceptionResolvers != null) {
      // 遍歷所有的異常解析器
      for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
        // 解析異常,核心的解析器是ExceptionHandlerExceptionResolver
        exMv = resolver.resolveException(request, response, handler, ex);
      }
    }
    // ...
  }
}

ExceptionHandlerExceptionResolver類繼承自AbstractHandlerMethodExceptionResolver該類又繼承自AbstractHandlerExceptionResolver。

// 調用父類(AbstractHandlerExceptionResolver)方法
public abstract class AbstractHandlerExceptionResolver implements HandlerExceptionResolver, Ordered {
  public ModelAndView resolveException(...) {
    // doResolveException該方法在子類AbstractHandlerMethodExceptionResolver中重寫
    ModelAndView result = doResolveException(request, response, handler, ex);
  }
}

AbstractHandlerMethodExceptionResolver

public abstract class AbstractHandlerMethodExceptionResolver extends AbstractHandlerExceptionResolver {
  protected final ModelAndView doResolveException(...) {
    HandlerMethod handlerMethod = (handler instanceof HandlerMethod hm ? hm : null);
    return doResolveHandlerMethodException(request, response, handlerMethod, ex);
  }
}

ExceptionHandlerExceptionResolver

public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver implements ApplicationContextAware, InitializingBean {
  protected ModelAndView doResolveHandlerMethodException(...) {
    // 該方法中會先從當前的Controller中查找是否有@ExceptionHandler注解的方法(如果匹配)
    // 如果沒有再從全局的異常處理類句柄中查找
    ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
    if (exceptionHandlerMethod == null) {
      return null;
    }
    // 執行異常處理方法的調用
    exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, arguments);
  }
  protected ServletInvocableHandlerMethod getExceptionHandlerMethod(...) {
    Class<?> handlerType = null;
    if (handlerMethod != null) {  
      handlerType = handlerMethod.getBeanType();
      // 緩存并設置當前執行Class對應的ExceptionHandlerMethodResolver
      // ExceptionHandlerMethodResolver構造函數中會解析當前類中的所有方法是否有@ExceptionHandler注解
      ExceptionHandlerMethodResolver resolver = this.exceptionHandlerCache.computeIfAbsent(handlerType, ExceptionHandlerMethodResolver::new);
      // 解析是否匹配當前發生的異常
      Method method = resolver.resolveMethod(exception);
      if (method != null) {
        return new ServletInvocableHandlerMethod(handlerMethod.getBean(), method, this.applicationContext);
      }
    }
    // 如果上面的執行的Class中沒有找到對應處理器,那么就從全局的異常處理中進行查找匹配
    // 這里的exceptionHandlerAdviceCache集合在類初始化執行時已經處理完成
    for (Map.Entry<ControllerAdviceBean, ExceptionHandlerMethodResolver> entry : this.exceptionHandlerAdviceCache.entrySet()) {
      ControllerAdviceBean advice = entry.getKey();
      if (advice.isApplicableToBeanType(handlerType)) {
        ExceptionHandlerMethodResolver resolver = entry.getValue();
        Method method = resolver.resolveMethod(exception);
        if (method != null) {
          return new ServletInvocableHandlerMethod(advice.resolveBean(), method, this.applicationContext);
        }
      }
    }
    return null;
  }
}

通過上面的源碼分析你應該知道了關于SpringMVC中異常處理的原理。

當上面的異常處理機制都沒法處理,那么將會調用默認的/error接口。

public class ErrorMvcAutoConfiguration {
  @Bean
  @ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
  public BasicErrorController basicErrorController(ErrorAttributes errorAttributes, ObjectProvider<ErrorViewResolver> errorViewResolvers) {
    return new BasicErrorController(errorAttributes, this.serverProperties.getError(), errorViewResolvers.orderedStream().toList());
  }  
}

BasicErrorController

@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
}

上面的錯誤接口/error在容器啟動時會自動注冊到內嵌的容器中,如:Tomcat。

責任編輯:武曉燕 來源: 實戰案例錦集
相關推薦

2011-03-17 09:20:05

異常處理機制

2010-03-05 15:40:16

Python異常

2023-03-08 08:54:59

SpringMVCJava

2011-07-21 15:20:41

java異常處理機制

2023-02-23 08:15:33

Spring異常處理機制

2021-03-02 09:12:25

Java異常機制

2009-08-05 18:09:17

C#異常處理機制

2011-04-06 10:27:46

Java異常處理

2024-03-04 10:00:35

數據庫處理機制

2021-07-03 17:53:52

Java異常處理機制

2009-09-02 18:34:28

C#鼠標事件

2021-03-25 07:44:39

C++異常處理開發技術

2015-12-28 11:25:51

C++異常處理機制

2011-07-01 14:20:59

Qt 事件

2011-07-01 14:14:34

Qt 事件

2025-06-09 01:15:00

2014-05-22 15:00:16

Android消息處理機制Looper

2014-05-22 15:04:00

Android消息處理機制Looper

2014-05-22 15:07:44

Android消息處理機制Looper

2014-05-22 15:38:27

Android消息處理機制Looper
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧产日产国产精品视频 | 成人亚洲综合 | 亚洲热在线视频 | 国产精品污污视频 | 播放一级毛片 | 日韩精品一区二区三区中文字幕 | 黄色一级片在线播放 | 日本午夜在线视频 | 国产成人在线一区二区 | 一区二区三区四区电影视频在线观看 | 欧美色综合一区二区三区 | 精品一区二区三区在线观看国产 | 毛片软件| 成人免费在线视频 | 日本在线免费观看 | 成人a网 | 涩爱av一区二区三区 | 久久久久久国模大尺度人体 | 日日夜夜免费精品 | www.99热 | 丝袜天堂 | 自拍偷拍第一页 | 四虎海外 | 亚洲视频在线观看 | jizz18国产| 午夜丰满寂寞少妇精品 | 又黑又粗又长的欧美一区 | 男女视频在线观看网站 | 中文字幕高清一区 | 亚洲看片网站 | 久久狼人天堂 | 在线色网址 | 免费看片国产 | 欧美久久久久久久久 | 亚洲精品久久久一区二区三区 | 久久国产一区二区三区 | aaa精品 | 欧美成年黄网站色视频 | 日韩在线精品 | 一本色道精品久久一区二区三区 | 亚洲精品久久久久久久久久吃药 |