HandlerAdapter之RequestMappingHandlerAdapter处理请求

一、类图

1.1 HandlerAdapter类图

HandlerAdapter之RequestMappingHandlerAdapter处理请求

 

1.2 RequestMappingHandlerAdapter类图

HandlerAdapter之RequestMappingHandlerAdapter处理请求

 

 

二、处理请求流程

(1) 检查给定请求的请求方法是否支持,是否必须有会话

(2) 创建WebDataBinderFactory:Handler整个继承体系上有@InitBinder注解的方法,以及@ControllerAdvice注解标注的类中有@InitBinder注解的方法

(3) 创建ModelFactory:获取Handler上的@SessionAttributes注解,获取Handler中没有标注@RequestMapping但标注了@ModelAttribute注解的方法,@ControllerAdvice注解标注的类中没有标注@RequestMapping但标注了@ModelAttribute注解的方法

(4) 创建ServletInvocableHandlerMethod:封装了HandlerMethod,设置HandlerMethodArgumentResolverComposite、HandlerMethodReturnValueHandlerComposite、WebDataBinderFactory、ParameterNameDiscoverer

(5) 创建ModelAndViewContainer:设置请求中的FlashMap(Input)

(6) 调用ModelFactory#initModel:按以下顺序往ModelAndViewContainer中填充model:

在session中检索{@code @SessionAttributes}注解指定的会话属性存在的值。

调用{@code @ModelAttribute}标注的方法,返回值保存到ModelAndViewContainer中。

查找{@code @ModelAttribute}标注的方法参数,先从ModelAndViewContainer获取,不存在的从session中获取,如果session中也没有抛出异常。

(7) 创建WebAsyncManager:异步处理使用

(8) 调用ServletInvocableHandlerMethod#invokeAndHandle方法处理请求:

找到匹配方法参数的HandlerMethodArgumentResolver,解析出参数

反射调用方法

根据方法返回值和返回值类型,找到匹配的HandlerMethodArgumentResolver,处理返回值

(9) 获取ModelAndView:根据ModelAndViewContainer、ModelFactory、ServletWebRequest获取ModelAndView

调用ModelFactory#updateModel方法:将{@code @SessionAttributes}指定的属性提升到会话。如有必要,添加{@link BindingResult}属性。

 

三、处理请求

3.1 AbstractHandlerMethodAdapter

3.1.1 是否支持Handler supports

AbstractHandlerMethodAdapter

public final boolean supports(Object handler) {

 // handler必须实现HandlerMethod接口,supportsInternal 留给子类实现,传送门:3.2.1

 return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));

}

 

3.1.2 调用Handler处理请求 handle

public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)

  throws Exception {

 

 // handleInternal 留给子类实现,传送门:3.2.2

 return handleInternal(request, response, (HandlerMethod) handler);

}

 

3.2 RequestMappingHandlerAdapter

3.2.1 是否支持处理当前Handler supportsInternal

protected boolean supportsInternal(HandlerMethod handlerMethod) {

 return true;

}

 

3.2.2 处理请求 handleInternal

protected ModelAndView handleInternal(HttpServletRequest request,

  HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

 

 ModelAndView mav;

 // 检查给定的请求以获取受支持的方法和所需的会话(如果有)

 checkRequest(request);

 

 // 如果需要,在同步块中执行invokeHandlerMethod

 if (this.synchronizeOnSession) {

  HttpSession session = request.getSession(false);

  if (session != null) {

   Object mutex = WebUtils.getSessionMutex(session);

   synchronized (mutex) {

    mav = invokeHandlerMethod(request, response, handlerMethod);

   }

  }

  else {

   // 没有可用的HttpSession->不需要同步块执行

   mav = invokeHandlerMethod(request, response, handlerMethod);

  }

 }

 else {

  // 不需要会话同步

  mav = invokeHandlerMethod(request, response, handlerMethod);

 }

 

 if (!response.containsHeader(HEADER_CACHE_CONTROL)) {

  if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {

   applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);

  }

  else {

   prepareResponse(response);

  }

 }

 

 return mav;

}

 

3.2.3 checkRequest

// 检查给定的请求以获取受支持的方法和所需的会话(如果有)

protected final void checkRequest(HttpServletRequest request) throws ServletException {

 // 检查是否支持请求方法

 String method = request.getMethod();

 if (this.supportedMethods != null && !this.supportedMethods.contains(method)) {

  throw new HttpRequestMethodNotSupportedException(method, this.supportedMethods);

 }

 

 // 检查是否需要会话

 if (this.requireSession && request.getSession(false) == null) {

  throw new HttpSessionRequiredException("Pre-existing session required but none found");

 }

}

 

3.2.4 invokeHandlerMethod

@ModelAttribute一般解决同一个Controller中共性问题(如果放在一个公共的Contrller父类,也可以解决多Controller间共性问题)。@ControllerAdvice主要解决多Contrller中的共性问题,如公共数据、全局异常处理、全局入参出参转换等。可包含@ExceptionHandler、@InitBinder、@ModelAttribute注解的方法,这些方法默认将对所有Contrller的@RequestMapping方法启用(可通过@ControllerAdvice属性值限制范围)

 

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,

  HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

 

 ServletWebRequest webRequest = new ServletWebRequest(request, response);

 try {

  // 数据绑定。获取整个继承体系上有@InitBinder注解的方法,以及@ControllerAdvice注解标注的类中有@InitBinder注解的方法。@InitBinder标注的方法可以设置数据绑定属性,比如:属性编辑器

  WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);

  // 往Model/Session中保存数据,从Model中获取数据

  ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

 

  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);

 

  ModelAndViewContainer mavContainer = new ModelAndViewContainer();

  // 从FlashMap中获取数据,之前请求保存的数据

  mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));

  // 1、处理@SessionAttributes注解

  // 2、调用@ModelAttribute注解标注的方法,并将返回值保存到mavContainer中。实际上保存在ModelAndViewContainer的ModelMap中

  // 3、解析方法参数上的@ModelAttribute注解,从@SessionAttributes标注的session中获取,保存到ModelMap中。

  modelFactory.initModel(webRequest, mavContainer, invocableMethod);

  // 默认情况下,在渲染和重定向方案中都使用“默认”模型的内容。另外,控制器方法可以声明{@code RedirectAttributes}类型的参数,并使用它提供属性以准备重定向URL。

  mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

 

  // ========================= 异步请 =========================

  AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);

  asyncWebRequest.setTimeout(this.asyncRequestTimeout);

 

  WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

  asyncManager.setTaskExecutor(this.taskExecutor);

  asyncManager.setAsyncWebRequest(asyncWebRequest);

  asyncManager.registerCallableInterceptors(this.callableInterceptors);

  asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

 // ========================= 异步请 =========================

 

  if (asyncManager.hasConcurrentResult()) {

   Object result = asyncManager.getConcurrentResult();

   mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];

   asyncManager.clearConcurrentResult();

   LogFormatUtils.traceDebug(logger, traceOn -> {

    String formatted = LogFormatUtils.formatValue(result, !traceOn);

    return "Resume with async result [" + formatted + "]";

   });

  // 创建一个嵌套的ServletInvocableHandlerMethod子类,该子类返回给定的值(如果该值为1,则引发Exception),而不是实际调用控制器方法。这在处理异步返回值(例如Callable,DeferredResult,ListenableFuture)时很有用。

   invocableMethod = invocableMethod.wrapConcurrentResult(result);

  }

 

  // 调用Handler方法处理请求,传送门3.3.1

  invocableMethod.invokeAndHandle(webRequest, mavContainer);

  if (asyncManager.isConcurrentHandlingStarted()) {

   return null;

  }

 

  return getModelAndView(mavContainer, modelFactory, webRequest);

 }

 finally {

  webRequest.requestCompleted();

 }

}

 

3.2.4.1 getDataBinderFactory

// 获取整个继承体系上有@InitBinder注解的方法,以及@ControllerAdvice注解标注的类中有@InitBinder注解的方法

private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {

 Class<?> handlerType = handlerMethod.getBeanType();

 // 初次获取为NULL

 Set<Method> methods = this.initBinderCache.get(handlerType);

 if (methods == null) {

  // 整个继承体系上获取有@InitBinder注解的方法

  methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);

  this.initBinderCache.put(handlerType, methods);

 }

 List<InvocableHandlerMethod> initBinderMethods = new ArrayList<>();

 // @ControllerAdvice注解标注的类中有@InitBinder注解的方法

 this.initBinderAdviceCache.forEach((clazz, methodSet) -> {

  // 是否能适用当前Handler

  if (clazz.isApplicableToBeanType(handlerType)) {

   Object bean = clazz.resolveBean();

   for (Method method : methodSet) {

    // 用InvocableHandlerMethod封装bean和method

    initBinderMethods.add(createInitBinderMethod(bean, method));

   }

  }

 });

 

 // 整个继承体系上有@InitBinder注解的方法,也加入到initBinderMethods

 for (Method method : methods) {

  Object bean = handlerMethod.getBean();

  initBinderMethods.add(createInitBinderMethod(bean, method));

 }

 return createDataBinderFactory(initBinderMethods);

}

 

3.2.4.2 getModelFactory

// 获取类上的@SessionAttributes注解,获取没有标注@RequestMapping但标注了@ModelAttribute注解的方法,标注了@ControllerAdvice注解的类中没有标注@RequestMapping但标注了@ModelAttribute注解的方法

private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {

 // 获取类上的@SessionAttributes注解

 SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);

 Class<?> handlerType = handlerMethod.getBeanType();

 Set<Method> methods = this.modelAttributeCache.get(handlerType);

 if (methods == null) {

  // 获取没有标注@RequestMapping但标注了@ModelAttribute注解的方法,数据预处理

  methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);

  this.modelAttributeCache.put(handlerType, methods);

 }

 List<InvocableHandlerMethod> attrMethods = new ArrayList<>();

 // this.modelAttributeAdviceCache是标注了@ControllerAdvice注解的类中没有标注@RequestMapping但标注了@ModelAttribute注解的方法

 this.modelAttributeAdviceCache.forEach((clazz, methodSet) -> {

  if (clazz.isApplicableToBeanType(handlerType)) {

   Object bean = clazz.resolveBean();

   for (Method method : methodSet) {

    attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));

   }

  }

 });

 for (Method method : methods) {

  Object bean = handlerMethod.getBean();

  // InvocableHandlerMethod封装了binderFactory, Handler, method

  attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));

 }

 return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);

}

 

3.2.4.3 获取类上的@SessionAttributes注解 getSessionAttributesHandler

// 获取类上的@SessionAttributes注解

private SessionAttributesHandler getSessionAttributesHandler(HandlerMethod handlerMethod) {

 Class<?> handlerType = handlerMethod.getBeanType();

 SessionAttributesHandler sessionAttrHandler = this.sessionAttributesHandlerCache.get(handlerType);

 if (sessionAttrHandler == null) {

  synchronized (this.sessionAttributesHandlerCache) {

   sessionAttrHandler = this.sessionAttributesHandlerCache.get(handlerType);

   if (sessionAttrHandler == null) {

    // 获取Handler上的@SessionAttributes注解

    sessionAttrHandler = new SessionAttributesHandler(handlerType, this.sessionAttributeStore);

    this.sessionAttributesHandlerCache.put(handlerType, sessionAttrHandler);

   }

  }

 }

 return sessionAttrHandler;

}

 

3.3.4.5 getModelAndView

private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,

  ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {

 

 // 将列为{@code @SessionAttributes}的模型属性提升到会话。 如有必要,添加{@link BindingResult}属性。

 modelFactory.updateModel(webRequest, mavContainer);

 

 // 请求是否已在处理程序中完全处理,响应已经写回客户端

 if (mavContainer.isRequestHandled()) {

  return null;

 }

 ModelMap model = mavContainer.getModel();

 ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());

 if (!mavContainer.isViewReference()) {

  mav.setView((View) mavContainer.getView());

 }

 if (model instanceof RedirectAttributes) {

  // 请求重定向,请求参数保存到FlashMap中

  Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();

  HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);

  if (request != null) {

   RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);

  }

 }

 return mav;

}

 

3.2.9 设置缓存时间 applyCacheSeconds

// 应用给定的缓存秒数并生成相应的HTTP标头,即在为正数的情况下允许缓存给定的秒数,如果给定值为0则阻止缓存,则不执行其他任何操作。 不告诉浏览器重新验证资源。

protected final void applyCacheSeconds(HttpServletResponse response, int cacheSeconds) {

 if (this.useExpiresHeader || !this.useCacheControlHeader) {

  // Deprecated HTTP 1.0 cache behavior, as in previous Spring versions

  if (cacheSeconds > 0) {

   cacheForSeconds(response, cacheSeconds);

  }

  else if (cacheSeconds == 0) {

   preventCaching(response);

  }

 }

 else {

  CacheControl cControl;

  if (cacheSeconds > 0) {

   cControl = CacheControl.maxAge(cacheSeconds, TimeUnit.SECONDS);

   if (this.alwaysMustRevalidate) {

    cControl = cControl.mustRevalidate();

   }

  }

  else if (cacheSeconds == 0) {

   cControl = (this.useCacheControlNoStore ? CacheControl.noStore() : CacheControl.noCache());

  }

  else {

   cControl = CacheControl.empty();

  }

  applyCacheControl(response, cControl);

 }

}

 

3.2.10 设置缓存控制请求头 applyCacheControl

// 根据给定的设置设置HTTP Cache-Control

protected final void applyCacheControl(HttpServletResponse response, CacheControl cacheControl) {

 String ccValue = cacheControl.getHeaderValue();

 if (ccValue != null) {

  // Set computed HTTP 1.1 Cache-Control header

  response.setHeader(HEADER_CACHE_CONTROL, ccValue);

 

  if (response.containsHeader(HEADER_PRAGMA)) {

   // Reset HTTP 1.0 Pragma header if present

   response.setHeader(HEADER_PRAGMA, "");

  }

  if (response.containsHeader(HEADER_EXPIRES)) {

   // Reset HTTP 1.0 Expires header if present

   response.setHeader(HEADER_EXPIRES, "");

  }

 }

}

 

3.3 ServletInvocableHandlerMethod

3.3.1 调用Handler方法处理请求 invokeAndHandle

// 3.2.4调用时为传入providedArgs参数值,providedArgs为NULL

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,

  Object... providedArgs) throws Exception {

 

 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);

 setResponseStatus(webRequest);

 

 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;

 }

 

 mavContainer.setRequestHandled(false);

 Assert.state(this.returnValueHandlers != null, "No return value handlers");

 try {

  // 根据返回值和返回值类型获取HandlerMethodReturnValueHandler

  this.returnValueHandlers.handleReturnValue(

    returnValue, getReturnValueType(returnValue), mavContainer, webRequest);

 }

 catch (Exception ex) {

  if (logger.isTraceEnabled()) {

   logger.trace(formatErrorForReturnValue(returnValue), ex);

  }

  throw ex;

 }

}

 

3.3.2 setResponseStatus

// 根据{@link ResponseStatus}注解设置响应状态

private void setResponseStatus(ServletWebRequest webRequest) throws IOException {

 // 获取的是HandlerMethod.responseStatus

 HttpStatus status = getResponseStatus();

 if (status == null) {

  return;

 }

 

 HttpServletResponse response = webRequest.getResponse();

 if (response != null) {

  String reason = getResponseStatusReason();

  if (StringUtils.hasText(reason)) {

   response.sendError(status.value(), reason);

  }

  else {

   response.setStatus(status.value());

  }

 }

 

 // To be picked up by RedirectView

 webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status);

}

 

3.4 InvocableHandlerMethod

3.4.1 获取参数调用Handler方法 invokeForRequest

// 3.2.4调用时为传入providedArgs参数值,providedArgs为NULL

public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,

  Object... providedArgs) throws Exception {

 

  // 如果providedArgs没有匹配的参数值,获取匹配参数的HandlerMethodArgumentResolver解析参数

 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);

 if (logger.isTraceEnabled()) {

  logger.trace("Arguments: " + Arrays.toString(args));

 }

 return doInvoke(args);

}

 

3.4.2 获取方法参数 getMethodArgumentValues

// 3.2.4调用时为传入providedArgs参数值,providedArgs为NULL

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 parameter = parameters[i];

  parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);

  // 调用的是HandlerMethod#findProvidedArgument方法

  args[i] = findProvidedArgument(parameter, providedArgs);

  if (args[i] != null) {

   continue;

  }

 

  // 是否有匹配的HandlerMethodArgumentResolver,比如:@RequestBody、@PathVariable等

  if (!this.resolvers.supportsParameter(parameter)) {

   throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));

  }

  try {

   // 根据不同HandlerMethodArgumentResolver解析出参数值,比如从请求头、请求参数、请求路径变量等

   args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);

  }

  catch (Exception ex) {

   if (logger.isDebugEnabled()) {

    String exMsg = ex.getMessage();

    if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {

     logger.debug(formatArgumentError(parameter, exMsg));

    }

   }

   throw ex;

  }

 }

 return args;

}

 

 

3.4.3 执行Handler方法 doInvoke

protected Object doInvoke(Object... args) throws Exception {

 ReflectionUtils.makeAccessible(getBridgedMethod());

 try {

  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);

  }

 }

}

 

3.5 HandlerMethod

3.5.1 获取方法参数值 findProvidedArgument

// 根据是否是参数类型的实例返回参数组。3.2.4调用时为传入providedArgs参数值,providedArgs为NULL

protected static Object findProvidedArgument(MethodParameter parameter, @Nullable Object... providedArgs) {

 if (!ObjectUtils.isEmpty(providedArgs)) {

  for (Object providedArg : providedArgs) {

   if (parameter.getParameterType().isInstance(providedArg)) {

    return providedArg;

   }

  }

 }

 return null;

}