該系列文檔是本人在學習 Spring MVC 的源碼過程當中總結下來的,可能對讀者不太友好,請結合個人源碼註釋 Spring MVC 源碼分析 GitHub 地址 進行閱讀html
Spring 版本:5.2.4.RELEASEjava
該系列其餘文檔請查看:《精盡 Spring MVC 源碼分析 - 文章導讀》git
HandlerAdapter 組件,處理器的適配器。由於處理器 handler
的類型是 Object 類型,須要有一個調用者來實現 handler
是怎麼被執行。Spring 中的處理器的實現多變,好比用戶的處理器能夠實現 Controller 接口或者 HttpRequestHandler 接口,也能夠用 @RequestMapping
註解將方法做爲一個處理器等,這就致使 Spring MVC 沒法直接執行這個處理器。因此這裏須要一個處理器適配器,由它去執行處理器github
因爲 HandlerMapping 組件涉及到的內容較多,考慮到內容的排版,因此將這部份內容拆分紅了五個模塊,依次進行分析:web
本文是接着《HandlerAdapter 組件(一)之 HandlerAdapter》一文來分享 ServletInvocableHandlerMethod 組件。在 HandlerAdapter
執行處理器的過程當中,主要的任務仍是交由它來完成的。ServletInvocableHandlerMethod 封裝 HandlerMethod
處理器對象,它還包含 HandlerMethodArgumentResolver
參數解析器和 HandlerMethodReturnValueHandler
返回值處理器等組件。雖然內容很少,但仍是有必要另外一篇進行分析。spring
先來回顧一下 RequestMappingHandlerAdapter
是如何建立 ServletInvocableHandlerMethod 對象的,能夠回到 《HandlerAdapter 組件(一)之 HandlerAdapter》 中 RequestMappingHandlerAdapter 小節下面的 invokeHandlerMethod
方法,以下:數組
@Nullable protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { // ... 省略相關代碼 // <4> 建立 ServletInvocableHandlerMethod 對象,並設置其相關屬性 ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); if (this.argumentResolvers != null) { invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); } if (this.returnValueHandlers != null) { invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); } invocableMethod.setDataBinderFactory(binderFactory); invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); // ... 省略相關代碼 // <9> 執行調用 invocableMethod.invokeAndHandle(webRequest, mavContainer); // ... 省略相關代碼 } protected ServletInvocableHandlerMethod createInvocableHandlerMethod(HandlerMethod handlerMethod) { return new ServletInvocableHandlerMethod(handlerMethod); }
將 HandlerMethod
處理器封裝成 ServletInvocableHandlerMethod 對象,而後設置參數解析器和返回值處理器mvc
這裏設置了 ServletInvocableHandlerMethod 對象的 resolvers
、parameterNameDiscoverer
和 returnValueHandlers
相關屬性app
調用invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs)
方法,執行處理器ide
ServletInvocableHandlerMethod 的總體類圖以下:
依次分析
org.springframework.web.method.HandlerMethod
,處理器的方法的封裝對象
在《HandlerMapping 組件(三)之 AbstractHandlerMethodMapping》的 AbstractHandlerMethodMapping 小節中已經分析過該對象
org.springframework.web.method.support.InvocableHandlerMethod
,繼承 HandlerMethod 類,可 invoke 調用的 HandlerMethod 實現類。
😈 也就是說,HandlerMethod 只提供了處理器的方法的基本信息,不提供調用邏輯。
public class InvocableHandlerMethod extends HandlerMethod { /** 無參時的入參,空數組 */ private static final Object[] EMPTY_ARGS = new Object[0]; /** 數據綁定器工廠 */ @Nullable private WebDataBinderFactory dataBinderFactory; /** 參數解析器組合對象 */ private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite(); /** 方法的參數名稱發現器 */ private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer(); }
invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs)
方法,執行請求,方法以下:
@Nullable public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // <1> 解析參數 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) { logger.trace("Arguments: " + Arrays.toString(args)); } // <2> 執行調用 return doInvoke(args); }
調用 getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs)
方法,解析方法的參數們,以下:
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 得到方法的參數 MethodParameter[] parameters = getMethodParameters(); // 無參,返回空數組 if (ObjectUtils.isEmpty(parameters)) { return EMPTY_ARGS; } // 將參數解析成對應的類型 Object[] args = new Object[parameters.length]; for (int i = 0; i < parameters.length; i++) { // 得到當前遍歷的 MethodParameter 對象,並設置 parameterNameDiscoverer 到其中 MethodParameter parameter = parameters[i]; parameter.initParameterNameDiscovery(this.parameterNameDiscoverer); // <1> 先從 providedArgs 中得到參數。若是得到到,則進入下一個參數的解析,默認狀況 providedArgs 不會傳參 args[i] = findProvidedArgument(parameter, providedArgs); if (args[i] != null) { continue; } // <2> 判斷 resolvers 是否支持當前的參數解析 if (!this.resolvers.supportsParameter(parameter)) { throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver")); } try { // 執行解析,解析成功後,則進入下一個參數的解析 args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); } catch (Exception ex) { // Leave stack trace for later, exception may actually be resolved and handled... if (logger.isDebugEnabled()) { String exMsg = ex.getMessage(); if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) { logger.debug(formatArgumentError(parameter, exMsg)); } } throw ex; } } return args; }
providedArgs
中得到參數。若是得到到,則進入下一個參數的解析。默認狀況下,providedArgs
參數不會傳遞,因此能夠暫時先忽略。保證核心邏輯的理解argumentResolvers
是否支持當前的參數解析。若是支持,則進行解析。關於 HandlerMethodArgumentResolverComposite 的詳細解析,見《HandlerAdapter 組件(三)之 HandlerMethodArgumentResolver》調用 doInvoke(Object... args)
方法,執行方法的調用,方法以下:
@Nullable protected Object doInvoke(Object... args) throws Exception { // <1> 設置方法爲可訪問 ReflectionUtils.makeAccessible(getBridgedMethod()); try { // <2> 執行調用 return getBridgedMethod().invoke(getBean(), args); } catch (IllegalArgumentException ex) { assertTargetBean(getBridgedMethod(), getBean(), args); String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument"); throw new IllegalStateException(formatInvokeError(text, args), ex); } catch (InvocationTargetException ex) { // Unwrap for HandlerExceptionResolvers ... Throwable targetException = ex.getTargetException(); if (targetException instanceof RuntimeException) { throw (RuntimeException) targetException; } else if (targetException instanceof Error) { throw (Error) targetException; } else if (targetException instanceof Exception) { throw (Exception) targetException; } else { throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException); } } }
注意,這裏獲取到的 Method 對象多是橋接方法,橋接方法:若是泛型對象,編譯器則會自動生成一個橋接方法(java1.5向後兼容)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod
,繼承 InvocableHandlerMethod 類,用於 DispatcherServlet 執行 HandlerMethod 處理器
public class ServletInvocableHandlerMethod extends InvocableHandlerMethod { private static final Method CALLABLE_METHOD = ClassUtils.getMethod(Callable.class, "call"); /** 返回結果處理器組合對象 */ @Nullable private HandlerMethodReturnValueHandlerComposite returnValueHandlers; public ServletInvocableHandlerMethod(Object handler, Method method) { super(handler, method); } public ServletInvocableHandlerMethod(HandlerMethod handlerMethod) { super(handlerMethod); } }
invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs)
方法,處理請求,執行處理器,並處理返回結果,方法以下:
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; } }
調用 InvocableHandlerMethod 父類的 invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs)
方法,執行調用
調用 setResponseStatus(ServletWebRequest webRequest)
設置響應的狀態碼,方法以下:
private void setResponseStatus(ServletWebRequest webRequest) throws IOException { // 得到狀態碼,和 @ResponseStatus 註解相關 HttpStatus status = getResponseStatus(); if (status == null) { return; } // 設置響應的狀態碼 HttpServletResponse response = webRequest.getResponse(); if (response != null) { String reason = getResponseStatusReason(); if (StringUtils.hasText(reason)) { // 有 reason ,則設置 status + reason response.sendError(status.value(), reason); } else { // 無 reason ,則僅設置 status response.setStatus(status.value()); } } // To be picked up by RedirectView // 爲了 RedirectView ,因此進行設置 webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status); }
設置 ModelAndViewContainer 爲請求已處理,返回,和 @ResponseStatus 註解相關
設置 ModelAndViewContainer 爲請求未處理
調用 HandlerMethodReturnValueHandlerComposite
的 handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
方法,處理返回值。詳細解析,見《HandlerAdapter 組件(四)之 HandlerMethodReturnValueHandler》
在 HandlerAdapter
執行 HandlerMethod
處理器的過程當中,會將該處理器封裝成 ServletInvocableHandlerMethod 對象,經過該對象來執行處理器。由於 HandlerMethod
處理器裏面僅包含了方法的全部信息,如何解析參數、調用對應的方法、以及處理返回結果,它自己並不知道如何去處理,這裏 Spring MVC 藉助於 ServletInvocableHandlerMethod 對象來進行操做,原理就是經過反射機制執行該方法
其中涉及到的 HandlerMethodArgumentResolver
參數解析器和 HandlerMethodReturnValueHandler
返回值處理器是比較關鍵的兩個組件,在接下來會逐個進行分析
參考文章:芋道源碼《精盡 Spring MVC 源碼分析》