SpringMVC 通過三層繼承體系封裝控制器方法調用全流程:
HandlerMethodArgumentResolver。@ResponseStatus 支持,適配 Servlet 環境。
public class HandlerMethod {
protected final Log logger = LogFactory.getLog(HandlerMethod.class);
private final Object bean; // Controller 實例或 Bean 名稱
private final Method method; // 處理方法
private final BeanFactory beanFactory; // 容器引用,用於解析 Bean 名稱
private final MethodParameter[] parameters; // 方法參數元數據(含返回值 index=-1)
private final Method bridgedMethod; // 橋接方法(泛型擦除產生)
// 關鍵方法:若 bean 為 String(Bean 名),從容器獲取實例返回新 HandlerMethod
public HandlerMethod createWithResolvedBean() {
Object handler = this.bean;
if (this.bean instanceof String) {
handler = this.beanFactory.getBean((String) this.bean);
}
return new HandlerMethod(this, handler);
}
}
MethodParameter 封裝單個參數完整信息:Method/Constructor、參數索引、類型、泛型、注解、參數名(需 ParameterNameDiscoverer 支持)、嵌套層級等。
public class InvocableHandlerMethod extends HandlerMethod {
private HandlerMethodArgumentResolverComposite argumentResolvers;
private WebDataBinderFactory dataBinderFactory;
private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
// 核心:構建方法調用實參數組
private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) {
MethodParameter[] params = getMethodParameters();
Object[] args = new Object[params.length];
for (int i = 0; i < params.length; i++) {
MethodParameter param = params[i];
param.initParameterNameDiscovery(parameterNameDiscoverer);
GenericTypeResolver.resolveParameterType(param, getBean().getClass());
// 1. 優先從 providedArgs(如 @ModelAttribute 預置對象)按類型匹配
args[i] = resolveProvidedArgument(param, providedArgs);
if (args[i] != null) continue;
// 2. 委派參數解析器解析(@RequestParam, @PathVariable, @RequestBody 等)
if (argumentResolvers.supportsParameter(param)) {
args[i] = argumentResolvers.resolveArgument(param, mavContainer, request, dataBinderFactory);
continue;
}
// 3. 無解析器支持則拋異常
throw new IllegalStateException("No suitable resolver for argument " + i);
}
return args;
}
// 實際調用:設置可訪問性、異常解包
private Object invoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
return getBridgedMethod().invoke(getBean(), args);
} catch (InvocationTargetException e) {
Throwable target = e.getTargetException();
if (target instanceof RuntimeException) throw (RuntimeException) target;
if (target instanceof Error) throw (Error) target;
if (target instanceof Exception) throw (Exception) target;
throw new IllegalStateException("Invocation failed", target);
}
}
}
public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
private ResponseStatus responseStatus; // @ResponseStatus 註解信息
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
// 入口:DispatcherServlet 處理器調用鏈最終調用此方法
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) {
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); // 父類調用
setResponseStatus(webRequest); // 處理 @ResponseStatus
// 判斷請求是否已完成(無返回值 + 無狀態碼 + 未標記 handled)
if (returnValue == null) {
if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
} else if (StringUtils.hasText(responseReason)) { // 有錯誤原因視為已處理
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
// 委派返回值處理器(View, @ResponseBody, HttpEntity, Model 等)
returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
private void setResponseStatus(ServletWebRequest webRequest) throws IOException {
if (responseStatus == null) return;
if (StringUtils.hasText(responseReason)) {
webRequest.getResponse().sendError(responseStatus.value(), responseReason);
} else {
webRequest.getResponse().setStatus(responseStatus.value());
}
// 供 RedirectView 檢測
webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, responseStatus);
}
}
| 組件 | 職責 | 擴展接口 | 典型實現 |
|---|---|---|---|
| 參數解析 | 將請求數據轉換為方法參數 | HandlerMethodArgumentResolver | RequestParamMethodArgumentResolver, RequestResponseBodyMethodProcessor |
| 返回值處理 | 將方法返回值轉換為響應 | HandlerMethodReturnValueHandler | ViewMethodReturnValueHandler, RequestResponseBodyMethodProcessor |
| 數據綁定 | 表單數據綁定到對象、校驗 | WebDataBinder + Validator | ConfigurableWebBindingInitializer |
DispatcherServlet.doDispatch() 入手,追蹤 HandlerAdapter.handle() → ServletInvocableHandlerMethod.invokeAndHandle()。HandlerMethodArgumentResolverComposite 的順序優先級機制(Ordered 接口)。ModelAndViewContainer 作為請求處理上下文的狀態流轉(requestHandled、redirectModel 等)。providedArgs 在 @ModelAttribute、@SessionAttributes 等場景下的注入過程。