1. 程式人生 > >精盡Spring MVC原始碼分析 - HandlerAdapter 元件(四)之 HandlerMethodReturnValueHandler

精盡Spring MVC原始碼分析 - HandlerAdapter 元件(四)之 HandlerMethodReturnValueHandler

> 該系列文件是本人在學習 Spring MVC 的原始碼過程中總結下來的,可能對讀者不太友好,請結合我的原始碼註釋 [Spring MVC 原始碼分析 GitHub 地址](https://github.com/liu844869663/spring-framework) 進行閱讀 > > Spring 版本:5.2.4.RELEASE > > 該系列其他文件請檢視:[**《精盡 Spring MVC 原始碼分析 - 文章導讀》**](https://www.cnblogs.com/lifullmoon/p/14123963.html) ## HandlerAdapter 元件 HandlerAdapter 元件,處理器的介面卡。因為處理器 `handler` 的型別是 Object 型別,需要有一個呼叫者來實現 `handler` 是怎麼被執行。Spring 中的處理器的實現多變,比如使用者的處理器可以實現 Controller 介面或者 HttpRequestHandler 介面,也可以用 `@RequestMapping` 註解將方法作為一個處理器等,這就導致 Spring MVC 無法直接執行這個處理器。所以這裡需要一個處理器介面卡,由它去執行處理器 由於 HandlerMapping 元件涉及到的內容較多,考慮到內容的排版,所以將這部分內容拆分成了五個模組,依次進行分析: - [**《HandlerAdapter 元件(一)之 HandlerAdapter》**](https://www.cnblogs.com/lifullmoon/p/14137467.html) - [**《HandlerAdapter 元件(二)之 ServletInvocableHandlerMethod》**](https://www.cnblogs.com/lifullmoon/p/14137483.html) - [**《HandlerAdapter 元件(三)之 HandlerMethodArgumentResolver》**](https://www.cnblogs.com/lifullmoon/p/14137494.html) - [**《HandlerAdapter 元件(四)之 HandlerMethodReturnValueHandler》**](https://www.cnblogs.com/lifullmoon/p/14137508.html) - [**《HandlerAdapter 元件(五)之 HttpMessageConverter》**](https://www.cnblogs.com/lifullmoon/p/14137520.html) ## HandlerAdapter 元件(四)之 HandlerMethodReturnValueHandler 本文是接著[**《HandlerAdapter 元件(三)之 HandlerMethodArgumentResolver》**](https://www.cnblogs.com/lifullmoon/p/14137494.html)一文來分享 **HandlerMethodReturnValueHandler** 元件。在 `HandlerAdapter` 執行處理器的過程中,具體的執行過程交由 `ServletInvocableHandlerMethod` 物件來完成,其中需要先通過 `HandlerMethodArgumentResolver` 引數解析器從請求中解析出方法的入參,然後再通過反射機制呼叫對應的方法,獲取到執行結果後需要通過 **HandlerMethodReturnValueHandler** 結果處理器來進行處理。 ### 回顧 先來回顧一下 `ServletInvocableHandlerMethod` 在哪裡呼叫返回值處理器的,可以回到 [**《HandlerAdapter 元件(二)之 ServletInvocableHandlerMethod》**](https://www.cnblogs.com/lifullmoon/p/14137483.html) 中 **ServletInvocableHandlerMethod** 小節下面的 `invokeAndHandle` 方法,如下: ```java public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // <1> 執行呼叫 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); // <2> 設定響應狀態碼 setResponseStatus(webRequest); // <3> 設定 ModelAndViewContainer 為請求已處理,返回,和 @ResponseStatus 註解相關 if (returnValue == null) { if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) { disableContentCachingIfNecessary(webRequest); mavContainer.setRequestHandled(true); return; } } else if (StringUtils.hasText(getResponseStatusReason())) { mavContainer.setRequestHandled(true); return; } // <4> 設定 ModelAndViewContainer 為請求未處理 mavContainer.setRequestHandled(false); Assert.state(this.returnValueHandlers != null, "No return value handlers"); try { // <5> 處理返回值 this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(formatErrorForReturnValue(returnValue), ex); } throw ex; } } ``` - `<5>` 處呼叫 `returnValueHandlers` 對返回結果進行處理 - `returnValueHandlers` 為 HandlerMethodReturnValueHandlerComposite 組合物件,包含了許多的結果處理器 ### HandlerMethodReturnValueHandler 介面 `org.springframework.web.method.support.HandlerMethodReturnValueHandler`,返回結果處理器 ```java public interface HandlerMethodReturnValueHandler { /** * 是否支援該型別 */ boolean supportsReturnType(MethodParameter returnType); /** * 處理返回值 */ void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception; } ``` ### 類圖
因為返回結果型別是多變的,所以會有許多的 HandlerMethodReturnValueHandler 的實現類,上圖僅列出了本文會分析的兩個實現類 ### ModelAndViewContainer `org.springframework.web.method.support.ModelAndViewContainer`,主要是作為 Model 和 View 的容器 #### 構造方法 ```java public class ModelAndViewContainer { /** * 是否在 redirect 重定向時,忽略 {@link #redirectModel} */ private boolean ignoreDefaultModelOnRedirect = false; /** * 檢視,Object 型別。 * * 實際情況下,也可以是 String 型別的邏輯檢視 */ @Nullable private Object view; /** * 預設使用的 Model 。實際上是個 Map */ private final ModelMap defaultModel = new BindingAwareModelMap(); /** * redirect 重定向的 Model ,在重定向時使用。 */ @Nullable private ModelMap redirectModel; /** * 處理器返回 redirect 檢視的標識 */ private boolean redirectModelScenario = false; /** * Http 響應狀態 */ @Nullable private HttpStatus status; private final Set noBinding = new HashSet<>(4); private final Set bindingDisabled = new HashSet<>(4); /** * 用於設定 SessionAttribute 的標識 */ private final SessionStatus sessionStatus = new SimpleSessionStatus(); /** * 請求是否處理完的標識 */ private boolean requestHandled = false; } ``` #### getModel `getModel()` 方法,獲得 Model 物件。程式碼如下: ```java public ModelMap getModel() { // 是否使用預設 Model if (useDefaultModel()) { return this.defaultModel; } else { if (this.redirectModel == null) { this.redirectModel = new ModelMap(); } return this.redirectModel; } } /** * Whether to use the default model or the redirect model. */ private boolean useDefaultModel() { return (!this.redirectModelScenario || (this.redirectModel == null && !this.ignoreDefaultModelOnRedirect)); } ``` - 從程式碼中,可以看出,有兩種情況下,使用 `defaultModel` 預設 Model : - 情況一 `!this.redirectModelScenario` ,處理器返回 redirect 檢視的標識為 `false` 的時候,即不重定向 - 情況二 `this.redirectModel == null && !this.ignoreDefaultModelOnRedirect` ,`redirectModel` 重定向 Model 為**空**,並且 `ignoreDefaultModelOnRedirect` 為 `true` ,即忽略 `defaultModel` - 那麼,問題就來了,redirectModelScenario 和 ignoreDefaultModelOnRedirect 什麼時候被改變? - `redirectModelScenario` 屬性,在下文的 **ViewNameMethodReturnValueHandler**的**handleReturnValue**方法中會設定為`true`,詳情見下文 - `ignoreDefaultModelOnRedirect` 屬性,和 RequestMappingHandlerAdapter 的 `ignoreDefaultModelOnRedirect` 的屬性是一致的,預設為`false` 在 RequestMappingHandlerAdapter 的 `invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod)` 方法中,進行設定 - 另外,`org.springframework.ui.ModelMap` 是繼承 LinkedHashMap 類,並增加了部分常用方法,比較簡單 #### View 相關的方法 ```java public void setViewName(@Nullable String viewName) { this.view = viewName; } @Nullable public String getViewName() { return (this.view instanceof String ? (String) this.view : null); } public void setView(@Nullable Object view) { this.view = view; } @Nullable public Object getView() { return this.view; } public boolean isViewReference() { return (this.view instanceof String); } ``` #### requestHandled 屬性 請求是否處理完的標識 關於 `requestHandled` 的修改地方,實際在 Spring MVC 地方蠻多處都可以進行修改,例如: - 在本文的開始處,`ServletInvocableHandlerMethod` 物件的 `invokeAndHandle` 方法中,會先設定為 `false`,表示請求還未處理,再交由 HandlerMethodReturnValueHandler 結果處理器去處理 - 在後文的 `RequestResponseBodyMethodProcessor` 的 `handleReturnValue` 會設定為 `true` 處理完結果後,接下來 `RequestMappingHandlerAdapter` 需要通過 `ModelAndViewContainer` 獲取 `ModelAndView` 物件,會用到 `requestHandled` 這個屬性 ```java // RequestMappingHandlerAdapter.java @Nullable private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception { modelFactory.updateModel(webRequest, mavContainer); // 情況一,如果 mavContainer 已處理,則返回“空”的 ModelAndView 物件。 if (mavContainer.isRequestHandled()) { return null; } // 情況二,如果 mavContainer 未處理,則基於 `mavContainer` 生成 ModelAndView 物件 ModelMap model = mavContainer.getModel(); // 建立 ModelAndView 物件,並設定相關屬性 ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus()); if (!mavContainer.isViewReference()) { mav.setView((View) mavContainer.getView()); } if (model instanceof RedirectAttributes) { Map flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); if (request != null) { RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); } } return mav; } ``` 看到沒,如果已處理,則返回的 `ModelAndView` 物件為 `null` ### HandlerMethodReturnValueHandlerComposite `org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite`,實現 HandlerMethodReturnValueHandler 介面,複合的 HandlerMethodReturnValueHandler 實現類 #### 構造方法 ```java public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler { /** HandlerMethodReturnValueHandler 陣列 */ private final List returnValueHandlers = new ArrayList<>(); } ``` 在[**《HandlerAdapter 元件(一)之 HandlerAdapter》**](https://www.cnblogs.com/lifullmoon/p/14137467.html)的**RequestMappingHandlerAdapter**小節的 `getDefaultReturnValueHandlers` 方法中可以看到,預設的 `returnValueHandlers` 有哪些 HandlerMethodReturnValueHandler 實現類,注意這裡是有順序的新增哦 #### getReturnValueHandler `getReturnValueHandler(MethodParameter returnType)` 方法,獲得方法返回值對應的 HandlerMethodReturnValueHandler 物件,方法如下: ```java @Nullable private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) { for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) { if (handler.supportsReturnType(returnType)) { return handler; } } return null; } ``` 很簡單,遍歷所有的 HandlerMethodReturnValueHandler 實現類,如果支援這個返回結果,則直接返回 這裡為什麼不加快取呢? #### supportsReturnType `supportsReturnType(MethodParameter returnType)`方法,判斷是否支援該返回型別,方法如下: ```java @Override public boolean supportsReturnType(MethodParameter returnType) { return getReturnValueHandler(returnType) != null; } ``` 實際上就是呼叫 `getReturnValueHandler(MethodParameter returnType)` 方法,存在對應的 HandlerMethodReturnValueHandler 實現類表示支援 #### handleReturnValue `handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest)`方法,處理返回值,方法如下: ```java @Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { // 獲得 HandlerMethodReturnValueHandler 物件 HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); if (handler == null) { throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName()); } handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); } ``` 這裡好奇的是沒有呼叫 `getReturnValueHandler(MethodParameter returnType)`方法獲取對應的 HandlerMethodReturnValueHandler 物件,而是呼叫 `selectHandler(Object value, MethodParameter returnType)` 方法,方法如下: ```java @Nullable private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) { // 判斷是否為非同步返回值 boolean isAsyncValue = isAsyncReturnValue(value, returnType); // 遍歷 HandlerMethodReturnValueHandler 陣列,逐個判斷是否支援 for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) { if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) { continue; } // 如果支援,則返回 if (handler.supportsReturnType(returnType)) { return handler; } } return null; } private boolean isAsyncReturnValue(@Nullable Object value, MethodParameter returnType) { for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) { if (handler instanceof AsyncHandlerMethodReturnValueHandler && ((AsyncHandlerMethodReturnValueHandler) handler).isAsyncReturnValue(value, returnType)) { return true; } } return false; } ``` 在 `getReturnValueHandler(MethodParameter returnType)` 的基礎上,增加了**非同步**處理器 AsyncHandlerMethodReturnValueHandler 的判斷 ### 【重點】RequestResponseBodyMethodProcessor `org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor`,繼承 AbstractMessageConverterMethodProcessor 抽象類,處理方法引數添加了 `@RequestBody` 註解方法入參,或者處理方法添加了 `@ResponseBody` 註解的返回值。 因為前後端分離之後,後端基本是提供 Restful API ,所以 RequestResponseBodyMethodProcessor 成為了目前最常用的 HandlerMethodReturnValueHandler 實現類。
從圖中,我們也會發現,RequestResponseBodyMethodProcessor 也是 HandlerMethodArgumentResolver 的實現類。示例程式碼: ```java @RestController @RequestMapping("/user") public class UserController { @RequestMapping("/walks") public List walk(@RequestBody User user) { List users = new ArrayList(); users.add(new User().setUsername("nihao")); users.add(new User().setUsername("zaijian")); return users; } } ``` 雖然,`walks()` 方法的返回值沒新增 `@ResponseBody` 註解,但是 `@RestController` 註解,預設有 `@ResponseBody` 註解 #### 構造方法 ```java public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor { public RequestResponseBodyMethodProcessor(List> converters) { super(converters); } public RequestResponseBodyMethodProcessor(List> converters, @Nullable ContentNegotiationManager manager) { super(converters, manager); } public RequestResponseBodyMethodProcessor(List> converters, @Nullable List requestResponseBodyAdvice) { super(converters, null, requestResponseBodyAdvice); } public RequestResponseBodyMethodProcessor(List> converters, @Nullable ContentNegotiationManager manager, @Nullable List requestResponseBodyAdvice) { super(converters, manager, requestResponseBodyAdvice); } } ``` - `converters` 引數,HttpMessageConverter 陣列。關於 HttpMessageConverter,就是將返回結果設定到響應中,供客戶端獲取。例如,我們想要將 POJO 物件,返回成 JSON 資料給前端,就會使用到 MappingJackson2HttpMessageConverter 類。 - `requestResponseBodyAdvice` 引數,在父類 AbstractMessageConverterMethodArgumentResolver 中會將其轉換成 RequestResponseBodyAdviceChain 物件 `advice`,不知你是否還記得這個引數,來回顧一下: 在[**《HandlerAdapter 元件(一)之 HandlerAdapter》**](https://www.cnblogs.com/lifullmoon/p/14137467.html)的**RequestMappingHandlerAdapter**的**1.afterPropertiesSet 初始化方法**中,第一步就會初始化所有 ControllerAdvice 相關的類 然後在**1.4 getDefaultReturnValueHandlers**方法中,建立 RequestResponseBodyMethodProcessor 處理器時,會傳入 `requestResponseBodyAdvice` 引數 使用示例可以參考 [SpringMVC 中 @ControllerAdvice 註解的三種使用場景](https://www.cnblogs.com/lenve/p/10748453.html) #### supportsParameter 實現 `supportsParameter(MethodParameter returnType)` 方法,判斷是否支援處理該方法引數,方法如下: ```java @Override public boolean supportsParameter(MethodParameter parameter) { // 該引數是否有 @RequestBody 註解 return parameter.hasParameterAnnotation(RequestBody.class); } ``` 該方法引數是否有 `@RequestBody` 註解 #### resolveArgument 實現 `resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory)` 方法,從請求中解析出帶有 `@RequestBody` 註解的引數,方法如下: ```java @Override public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { parameter = parameter.nestedIfOptional(); // 從請求體中解析出方法入參物件 Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType()); String name = Conventions.getVariableNameForParameter(parameter); // 資料繫結相關 if (binderFactory != null) { WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name); if (arg != null) { validateIfApplicable(binder, parameter); if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) { throw new MethodArgumentNotValidException(parameter, binder.getBindingResult()); } } if (mavContainer != null) { mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult()); } } // 返回方法入參物件,如果有必要,則通過 Optional 獲取對應的方法入參 return adaptArgumentIfNecessary(arg, parameter); } ``` 呼叫`readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter, Type paramType)`方法,從請求體中解析出方法入參物件 #### 【核心】readWithMessageConverters 從請求體中解析出方法入參,方法如下: ```java @Override protected Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter, Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException { // <1> 建立 ServletServerHttpRequest 請求物件 HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); Assert.state(servletRequest != null, "No HttpServletRequest"); ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest); // <2> 讀取請求體中的訊息並轉換成入參物件 Object arg = readWithMessageConverters(inputMessage, parameter, paramType); // <3> 校驗方法入參物件 if (arg == null && checkRequired(parameter)) { throw new HttpMessageNotReadableException("Required request body is missing: " + parameter.getExecutable().toGenericString(), inputMessage); } return arg; } // AbstractMessageConverterMethodArgumentResolver.java @Nullable protected Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException { // <1> 獲取使用的 MediaType 物件 MediaType contentType; boolean noContentType = false; try { // <1.1> 從請求頭中獲取 "Content-Type" contentType = inputMessage.getHeaders().getContentType(); } catch (InvalidMediaTypeException ex) { throw new HttpMediaTypeNotSupportedException(ex.getMessage()); } if (contentType == null) { noContentType = true; // <1.2> 為空則預設為 application/octet-stream contentType = MediaType.APPLICATION_OCTET_STREAM; } // <2> 獲取方法引數的 containing class 和 目標型別,用於 HttpMessageConverter 解析 Class contextClass = parameter.getContainingClass(); Class targetClass = (targetType instanceof Class ? (Class) targetType : null); if (targetClass == null) { // 如果為空,則從方法引數中解析出來 ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter); targetClass = (Class) resolvableType.resolve(); } // <3> 獲取 HTTP 方法 HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null); Object body = NO_VALUE; // <4> 開始從請求中解析方法入參 EmptyBodyCheckingHttpInputMessage message; try { // <4.1> 將請求訊息物件封裝成 EmptyBodyCheckingHttpInputMessage,用於校驗是否有請求體,沒有的話設定為 `null` message = new EmptyBodyCheckingHttpInputMessage(inputMessage); // <4.2> 遍歷 HttpMessageConverter for (HttpMessageConverter converter : this.messageConverters) { Class> converterType = (Class>) converter.getClass(); GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter) converter : null); // 如果該 HttpMessageConverter 能夠讀取當前請求體解析出方法入參 if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) : (targetClass != null && converter.canRead(targetClass, contentType))) { // <4.2.1> 如果請求體不為空 if (message.hasBody()) { HttpInputMessage msgToUse = getAdvice().beforeBodyRead(message, parameter, targetType, converterType); // 通過該 HttpMessageConverter 從請求體中解析出方法入參物件 body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) : ((HttpMessageConverter) converter).read(targetClass, msgToUse)); // 呼叫 RequestResponseBodyAdvice 的 afterBodyRead 方法,存在 RequestBodyAdvice 則對方法入參進行修改 body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType); } // <4.2.2> 如果請求體為空,則無需解析請求體 else { // 呼叫 RequestResponseBodyAdvice 的 afterBodyRead 方法,存在 RequestBodyAdvice 則對方法入參進行修改 body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType); } break; } } } catch (IOException ex) { throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage); } // <5> 校驗解析出來的方法入參物件是否為空 if (body == NO_VALUE) { if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) || (noContentType && !message.hasBody())) { return null; } throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes); } // 列印日誌 MediaType selectedContentType = contentType; Object theBody = body; LogFormatUtils.traceDebug(logger, traceOn -> { String formatted = LogFormatUtils.formatValue(theBody, !traceOn); return "Read \"" + selectedContentType + "\" to [" + formatted + "]"; }); // <6> 返回方法入參物件 return body; } ``` 我們直接看到父類 AbstractMessageConverterMethodArgumentResolver 的 `readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,Type targetType)`這個核心方法,大致邏輯如下: 1. 獲取使用的 MediaType 物件 `contentType` 1. 從請求頭中獲取 `Content-Type` 2. 請求頭中沒有則設定為預設的型別 `application/octet-stream` 2. 獲取方法引數的 `containing class` 和 `targetClass 目標型別`,用於 HttpMessageConverter 解析 3. 獲取 HTTP 方法 4. 開始從請求中解析方法入參`Object body` 1. 將請求訊息物件封裝成 EmptyBodyCheckingHttpInputMessage,用於校驗是否有請求體,沒有的話設定為 `null` 2. 遍歷所有的 HttpMessageConverter 實現類,呼叫其 `canRead(Type type, @Nullable Class contextClass, @Nullable MediaType mediaType)`方法,判斷當前 HttpMessageConverter 實現類是否支援解析該方法入參,如果返回 `true`,則使用該 HttpMessageConverter 實現類進行解析 1. 如果請求體不為空,則通過該 HttpMessageConverter 從請求體中解析出方法入參物件 2. 如果請求體為空,則無需解析請求體 注意:上面不管請求體是否為空,都會呼叫 `RequestResponseBodyAdvice` 的 `afterBodyRead` 方法,存在 RequestBodyAdvice 則對方法入參進行修改 5. 校驗解析出來的方法入參物件是否為空,丟擲異常或者返回`null` 6. 返回方法入參物件`body` ------ 方法雖然很長,但是不難理解,大致邏輯就是找到合適的 HttpMessageConverter 實現類從請求體中獲取到方法入參物件 邏輯和下面的 `writeWithMessageConverters` 差不多,我們重點來看到下面這個方法