本篇应用的Spring版本为5.2.2.RELEASE

九大组件

SpringMVC简直所有的性能都由九大组件来实现,所以明确九大组件的作用,对于学习SpringMVC来说十分重要。

/** 文件上传解析器 */private MultipartResolver multipartResolver;/** 区域解析器,用于国际化 */private LocaleResolver localeResolver;/** 主题解析器 */private ThemeResolver themeResolver;/** Handler映射信息 */private List<HandlerMapping> handlerMappings;/** Handler适配器*/private List<HandlerAdapter> handlerAdapters;/** Handler执行异样解析器 */private List<HandlerExceptionResolver> handlerExceptionResolvers;/** 申请到视图的转换器 */private RequestToViewNameTranslator viewNameTranslator;/** SpringMVC容许重定向时携带参数,存在session中,用完就销毁,所以叫FlashMap */private FlashMapManager flashMapManager;/** 视图解析器 */private List<ViewResolver> viewResolvers;复制代码
  • HandlerMapping:Handler映射信息,依据申请携带的url信息查找处理器(Handler)。每个申请都须要对应的Handler解决。
  • HandlerAdapter:Handler适配器,SpringMVC没有间接调用处理器(Handler),而是通过HandlerAdapter来调用,次要是为了对立Handler的调用形式
  • ViewResolver:视图解析器,用来将字符串类型的视图名称解析为View类型的视图。ViewResolver须要找到渲染所用的模板和所用的技术(也就是视图的类型)进行渲染,具体的渲染过程则交由不同的视图本人实现。
  • MultipartResolver:文件上传解析器,次要用来解决文件上传申请
  • HandlerExceptionResolver:Handler执行异样解析器,用来对异样进行对立解决
  • RequestToViewNameTranslator:申请到视图的转换器
  • LocaleResolver:区域解析器,用于反对国际化
  • FlashMapManager:SpringMVC容许重定向时携带参数,存在session中,用完就销毁,所以叫FlashMap
  • ThemeResolver:主题解析器,用于反对不同的主题

九大组件中最重的的前三个,HandlerMapping、HandlerAdapter和ViewResolver,因为这是浏览源码时,避不开的三个组件。
《2020最新Java根底精讲视频教程和学习路线!》

调试筹备

搭建一个根本的Spring web我的项目即可

Controller局部

@Controllerpublic class IndexController {    @RequestMapping("/index/home")    public String home(String id, Student student, @RequestParam("code") String code) {        System.out.println(student.getName());        return "index";    }    @ResponseBody    @RequestMapping("/index/list")    public String list() {        return "success";    }}复制代码

Entity局部

public class Student {    private String name;    private Integer gender;   // getter、setter}复制代码

还是那句话,Spring源码十分宏大,不能只见树木不见森林,须要有针对性的浏览,所以本篇只须要关注主体流程即可。

外围办法

咱们都晓得,SpringMVC有一个用来散发申请的前端控制器DispatcherServlet,其中用来解决申请的办法就是doService,该办法定义如下

doService

/** * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch} * for the actual dispatching. */@Overrideprotected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { logRequest(request); // Keep a snapshot of the request attributes in case of an include, // to be able to restore the original attributes after the include. Map<String, Object> attributesSnapshot = null; if (WebUtils.isIncludeRequest(request)) {  attributesSnapshot = new HashMap<>();  Enumeration<?> attrNames = request.getAttributeNames();  while (attrNames.hasMoreElements()) {   String attrName = (String) attrNames.nextElement();   if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {    attributesSnapshot.put(attrName, request.getAttribute(attrName));   }  } } // Make framework objects available to handlers and view objects. request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); if (this.flashMapManager != null) {  FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);  if (inputFlashMap != null) {   request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));  }  request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());  request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); } try {  // 真正执行的办法  doDispatch(request, response); } finally {  if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {   // Restore the original attribute snapshot, in case of an include.   if (attributesSnapshot != null) {    restoreAttributesAfterInclude(request, attributesSnapshot);   }  } }}复制代码

doDispatch

doDispatch是doService中真正用来解决申请的办法

/** * 理论解决申请的办法 */protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try {  ModelAndView mv = null;  Exception dispatchException = null;  try {   // 校验是否是文件上传申请   processedRequest = checkMultipart(request);   multipartRequestParsed = (processedRequest != request);   // Determine handler for the current request.   // 为以后申请找到一个适合的处理器(Handler)   // 返回值是一个HandlerExecutionChain,也就是处理器执行链   mappedHandler = getHandler(processedRequest);   if (mappedHandler == null) {    noHandlerFound(processedRequest, response);    return;   }   // Determine handler adapter for the current request.   // 依据HandlerExecutionChain携带的Handler找到适合的HandlerAdapter   HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());   // Process last-modified header, if supported by the handler.   // 解决GET申请的缓存   String method = request.getMethod();   boolean isGet = "GET".equals(method);   if (isGet || "HEAD".equals(method)) {    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {     return;    }   }   // 执行拦截器的preHandle办法   if (!mappedHandler.applyPreHandle(processedRequest, response)) {    return;   }   // Actually invoke the handler.   // 利用HandlerAdapter来执行Handler里对应的解决办法   mv = ha.handle(processedRequest, response, mappedHandler.getHandler());   if (asyncManager.isConcurrentHandlingStarted()) {    return;   }   // 如果没有设置视图,则利用默认的视图名   applyDefaultViewName(processedRequest, mv);   // 执行拦截器的postHandle办法   mappedHandler.applyPostHandle(processedRequest, response, mv);  }  catch (Exception ex) {   dispatchException = ex;  }  catch (Throwable err) {   // As of 4.3, we're processing Errors thrown from handler methods as well,   // making them available for @ExceptionHandler methods and other scenarios.   dispatchException = new NestedServletException("Handler dispatch failed", err);  }  // 依据ModelAndView对象解析视图  processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) {  triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) {  triggerAfterCompletion(processedRequest, response, mappedHandler,    new NestedServletException("Handler processing failed", err)); } finally {  if (asyncManager.isConcurrentHandlingStarted()) {   // Instead of postHandle and afterCompletion   if (mappedHandler != null) {    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);   }  }  else {   // Clean up any resources used by a multipart request.   if (multipartRequestParsed) {    cleanupMultipart(processedRequest);   }  } }}复制代码

该办法就是SpringMVC解决申请的整体流程,其中波及到几个重要的办法。

getHandler

该办法定义如下

/** * Return the HandlerExecutionChain for this request. * 为这个request返回一个HandlerExecutionChain */@Nullableprotected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) {  for (HandlerMapping mapping : this.handlerMappings) {   HandlerExecutionChain handler = mapping.getHandler(request);   if (handler != null) {    return handler;   }  } } return null;}复制代码

调试信息如下

依据调试信息能够看出,getHandler办法次要是从List handlerMappings汇合中遍历查找一个适合的处理器(Handler),返回的后果是一个HandlerExecutionChain。而后再依据HandlerExecutionChain里携带的Handler去获取HandlerAdapter。

getHandlerAdapter

getHandlerAdapter办法定义如下

/**  * Return the HandlerAdapter for this handler object.  * @param handler the handler object to find an adapter for  * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.  */ protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {  if (this.handlerAdapters != null) {   for (HandlerAdapter adapter : this.handlerAdapters) {    if (adapter.supports(handler)) {     return adapter;    }   }  }  throw new ServletException("No adapter for handler [" + handler +    "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }复制代码

调试信息如下

同样getHandlerAdapter办法次要是从List handlerAdapters汇合中遍历查找一个适合的处理器适配器(HandlerAdapter),返回的后果是一个HandlerAdapter。

能够看到此处HandlerAdapter真正的实现类是RequestMappingHandlerAdapter。

processDispatchResult

processDispatchResult办法次要依据办法执行实现后封装的ModelAndView,转发到对应页面,定义如下

/** * Handle the result of handler selection and handler invocation, which is * either a ModelAndView or an Exception to be resolved to a ModelAndView. */private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,  @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,  @Nullable Exception exception) throws Exception { boolean errorView = false; if (exception != null) {  if (exception instanceof ModelAndViewDefiningException) {   logger.debug("ModelAndViewDefiningException encountered", exception);   mv = ((ModelAndViewDefiningException) exception).getModelAndView();  }  else {   Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);   mv = processHandlerException(request, response, handler, exception);   errorView = (mv != null);  } } // Did the handler return a view to render? if (mv != null && !mv.wasCleared()) {  // 次要调用该办法渲染视图  render(mv, request, response);  if (errorView) {   WebUtils.clearErrorRequestAttributes(request);  } } else {  if (logger.isTraceEnabled()) {   logger.trace("No view rendering, null ModelAndView returned.");  } } if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {  // Concurrent handling started during a forward  return; } if (mappedHandler != null) {  // Exception (if any) is already handled..  mappedHandler.triggerAfterCompletion(request, response, null); }}复制代码

render

render办法定义如下

/** * Render the given ModelAndView. * <p>This is the last stage in handling a request. It may involve resolving the view by name. * @param mv the ModelAndView to render * @param request current HTTP servlet request * @param response current HTTP servlet response * @throws ServletException if view is missing or cannot be resolved * @throws Exception if there's a problem rendering the view */protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { // Determine locale for request and apply it to the response. Locale locale =   (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale()); response.setLocale(locale); View view; String viewName = mv.getViewName(); if (viewName != null) {  // We need to resolve the view name.  // 依据给定的视图名称,解析获取View对象  view = resolveViewName(viewName, mv.getModelInternal(), locale, request);  if (view == null) {   throw new ServletException("Could not resolve view with name '" + mv.getViewName() +     "' in servlet with name '" + getServletName() + "'");  } } else {  // No need to lookup: the ModelAndView object contains the actual View object.  view = mv.getView();  if (view == null) {   throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +     "View object in servlet with name '" + getServletName() + "'");  } } // Delegate to the View object for rendering. if (logger.isTraceEnabled()) {  logger.trace("Rendering view [" + view + "] "); } try {  if (mv.getStatus() != null) {   response.setStatus(mv.getStatus().value());  }  view.render(mv.getModelInternal(), request, response); } catch (Exception ex) {  if (logger.isDebugEnabled()) {   logger.debug("Error rendering view [" + view + "]", ex);  }  throw ex; }}复制代码

resolveViewName

resolveViewName办法定义如下

@Nullableprotected View resolveViewName(String viewName, @Nullable Map<String, Object> model,  Locale locale, HttpServletRequest request) throws Exception { if (this.viewResolvers != null) {  for (ViewResolver viewResolver : this.viewResolvers) {   View view = viewResolver.resolveViewName(viewName, locale);   if (view != null) {    return view;   }  } } return null;}复制代码

调试信息如下

依据调试信息能够看到真正解析视图的ViewResolver的是InternalResourceViewResolver类,也就是咱们常常配置的一项类型

<!-- 定义视图文件解析 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/" /> <property name="suffix" value=".html" /></bean>复制代码

至此咱们就失去了SpringMVC解决申请的残缺逻辑

SpringMVC解决申请的整个流程曾经梳理分明了。

然而,有两个重要的问题没有解决,那就是:参数绑定和返回值解决。

因为在编写Controller外面的办法的时候,各种类型的参数都有,SpringMVC是怎么解决不同类型的参数的呢? > SpringMVC解决申请实现后,肯定会返回ModelAndView吗,如果加了@ResponseBody注解呢?

参数绑定

在整个流程中,还有一个最重要的办法,那就是真正执行handler的办法,参数的绑定和返回值的解决都在这个办法里,也就是

// Actually invoke the handler.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());复制代码

handle

handle办法的作用是依据申请参数,执行真正的解决办法,并且返回适合的ModelAndView对象,也有可能返回null。该办法定义如下 在AbstractHandlerMethodAdapter类中

/** * This implementation expects the handler to be an {@link HandlerMethod}. */@Override@Nullablepublic final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)  throws Exception { return handleInternal(request, response, (HandlerMethod) handler);}复制代码

能够看到这个办法实现只有一行代码

handleInternal

持续深刻handleInternal办法

@Overrideprotected ModelAndView handleInternal(HttpServletRequest request,  HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ModelAndView mav; // 校验指定的申请以获取受反对的办法类型(GET、POST等)和所需的session checkRequest(request); // Execute invokeHandlerMethod in synchronized block if required. if (this.synchronizeOnSession) {  HttpSession session = request.getSession(false);  if (session != null) {   Object mutex = WebUtils.getSessionMutex(session);   synchronized (mutex) {    mav = invokeHandlerMethod(request, response, handlerMethod);   }  }  else {   // No HttpSession available -> no mutex necessary   mav = invokeHandlerMethod(request, response, handlerMethod);  } } else {  // No synchronization on session demanded at all...  // 真正执行handler的办法  mav = invokeHandlerMethod(request, response, handlerMethod); } if (!response.containsHeader(HEADER_CACHE_CONTROL)) {  if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {   applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);  }  else {   prepareResponse(response);  } } return mav;}复制代码

invokeHandlerMethod

持续深刻invokeHandlerMethod办法

/** * Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView} * if view resolution is required. * 执行@RequestMapping标注的handler办法,如果须要解析视图就筹备一个ModelAndView */@Nullableprotected ModelAndView invokeHandlerMethod(HttpServletRequest request,  HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); try {  WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);  ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);  // HandlerMethod接口封装执行办法的信息,提供对办法参数,办法返回值,办法正文等的便捷拜访。  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能够看做ModelAndView的上下文容器,关联着Model和View的信息  ModelAndViewContainer mavContainer = new ModelAndViewContainer();  mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));  modelFactory.initModel(webRequest, mavContainer, invocableMethod);  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 + "]";   });   invocableMethod = invocableMethod.wrapConcurrentResult(result);  }  // 真正执行Handler的办法  invocableMethod.invokeAndHandle(webRequest, mavContainer);  if (asyncManager.isConcurrentHandlingStarted()) {   return null;  }  // 获取ModelAndeView对象  return getModelAndView(mavContainer, modelFactory, webRequest); } finally {  webRequest.requestCompleted(); }}复制代码

invokeAndHandle

invokeAndHandle办法的作用是执行并解决真正响应申请的办法,该办法定义如下

/** * Invoke the method and handle the return value through one of the * configured {@link HandlerMethodReturnValueHandler HandlerMethodReturnValueHandlers}. * @param webRequest the current request * @param mavContainer the ModelAndViewContainer for this request * @param providedArgs "given" arguments matched by type (not resolved) */public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,  Object... providedArgs) throws Exception { // 执行handler的办法 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 {  this.returnValueHandlers.handleReturnValue(    returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) {  if (logger.isTraceEnabled()) {   logger.trace(formatErrorForReturnValue(returnValue), ex);  }  throw ex; }}复制代码

invokeForRequest

/** * Invoke the method after resolving its argument values in the context of the given request. * <p>Argument values are commonly resolved through * {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}. * The {@code providedArgs} parameter however may supply argument values to be used directly, * i.e. without argument resolution. Examples of provided argument values include a * {@link WebDataBinder}, a {@link SessionStatus}, or a thrown exception instance. * Provided argument values are checked before argument resolvers. * <p>Delegates to {@link #getMethodArgumentValues} and calls {@link #doInvoke} with the * resolved arguments. * @param request the current request * @param mavContainer the ModelAndViewContainer for this request * @param providedArgs "given" arguments matched by type, not resolved * @return the raw value returned by the invoked method * @throws Exception raised if no suitable argument resolver can be found, * or if the method raised an exception * @see #getMethodArgumentValues * @see #doInvoke */@Nullablepublic Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,  Object... providedArgs) throws Exception { // 获取参数 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) {  logger.trace("Arguments: " + Arrays.toString(args)); } // 执行 return doInvoke(args);}复制代码

真正的执行无非就是通过反射invoke,所以更重要的是参数是如何绑定的,详情就在getMethodArgumentValues办法

getMethodArgumentValues

getMethodArgumentValues办法用于从request申请中获取真正的参数,返回的是Object数组,该办法定义如下

/** * Get the method argument values for the current request, checking the provided * argument values and falling back to the configured argument resolvers. * <p>The resulting array will be passed into {@link #doInvoke}. * @since 5.1.2 */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);  args[i] = findProvidedArgument(parameter, providedArgs);  if (args[i] != null) {   continue;  }  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;}复制代码

依据调试信息能够看到,用来解决申请参数的类是HandlerMethodArgumentResolver接口的实现类HandlerMethodArgumentResolverComposite,此时正在解决的参数是一个Student对象,并且曾经把值注绑定了,也就是说真正执行绑定的是办法resolveArgument

resolveArgument

resolveArgument是真正执行绑定的的办法

/** * Iterate over registered * {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers} * and invoke the one that supports it. * @throws IllegalArgumentException if no suitable argument resolver is found */@Override@Nullablepublic Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,  NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { // 获取适合的参数解析器 HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter); if (resolver == null) {  throw new IllegalArgumentException("Unsupported parameter type [" +    parameter.getParameterType().getName() + "]. supportsParameter should be called first."); } // 执行参数绑定 return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);}复制代码

getArgumentResolver

getArgumentResolver该办法用于执行参数的绑定,定义如下

/** * Find a registered {@link HandlerMethodArgumentResolver} that supports * the given method parameter. */@Nullableprivate HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) { HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter); if (result == null) {  for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {   if (resolver.supportsParameter(parameter)) {    result = resolver;    this.argumentResolverCache.put(parameter, result);    break;   }  } } return result;}复制代码

该办法的逻辑就是先从argumentResolver缓存中找到可能执行参数绑定的HandlerMethodArgumentResolver,如果找不到就从HandlerMethodArgumentResolver找,SpringMVC反对的HandlerMethodArgumentResolver一共有26种,用来解析各种类型的参数

依据博主的调试能够晓得

  • RequestParamMethodArgumentResolver:解决一般参数(根本类型、包装类型、String),不论加不加@RequestParam注解
  • ServletModelAttributeMethodProcessor:解决POJO类型的参数,比方自定义的Student对象
  • RequestResponseBodyMethodProcessor:解决@RequestBody注解类型的参数

resolveArgument

因为不同类型的参数有不同的HandlerMethodArgumentResolver来解决,此处选取POJO类型参数的注入实现,对应的参数解析类是ModelAttributeMethodProcessor,其中resolveArgument办法用来解析(绑定)参数办法定义如下

/** * Resolve the argument from the model or if not found instantiate it with * its default if it is available. The model attribute is then populated * with request values via data binding and optionally validated * if {@code @java.validation.Valid} is present on the argument. * @throws BindException if data binding and validation result in an error * and the next method parameter is not of type {@link Errors} * @throws Exception if WebDataBinder initialization fails */@Override@Nullablepublic final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,  NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer"); Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory"); // 获取参数名 String name = ModelFactory.getNameForParameter(parameter); // 获取参数上的ModelAttribute注解 ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class); if (ann != null) {  mavContainer.setBinding(name, ann.binding()); } Object attribute = null; BindingResult bindingResult = null; if (mavContainer.containsAttribute(name)) {  attribute = mavContainer.getModel().get(name); } else {  // Create attribute instance  try {   // 创立参数类型的实例(未注入值),底层就是通过反射调用构造方法   attribute = createAttribute(name, parameter, binderFactory, webRequest);  }  catch (BindException ex) {   if (isBindExceptionRequired(parameter)) {    // No BindingResult parameter -> fail with BindException    throw ex;   }   // Otherwise, expose null/empty value and associated BindingResult   if (parameter.getParameterType() == Optional.class) {    attribute = Optional.empty();   }   bindingResult = ex.getBindingResult();  } } if (bindingResult == null) {  // Bean property binding and validation;  // skipped in case of binding failure on construction.  WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);  if (binder.getTarget() != null) {   if (!mavContainer.isBindingDisabled(name)) {    // 真正执行绑定(值注入)的办法    bindRequestParameters(binder, webRequest);   }   validateIfApplicable(binder, parameter);   if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {    throw new BindException(binder.getBindingResult());   }  }  // Value type adaptation, also covering java.util.Optional  if (!parameter.getParameterType().isInstance(attribute)) {   attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);  }  bindingResult = binder.getBindingResult(); } // Add resolved attribute and BindingResult at the end of the model Map<String, Object> bindingResultModel = bindingResult.getModel(); mavContainer.removeAttributes(bindingResultModel); mavContainer.addAllAttributes(bindingResultModel); return attribute;}复制代码

依据调试信息也能够看到bindRequestParameters(binder, webRequest)执行实现之后,POJO类型的参数曾经实现了绑定。

bindRequestParameters

/** * This implementation downcasts {@link WebDataBinder} to * {@link ServletRequestDataBinder} before binding. * @see ServletRequestDataBinderFactory */@Overrideprotected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) { ServletRequest servletRequest = request.getNativeRequest(ServletRequest.class); Assert.state(servletRequest != null, "No ServletRequest"); ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder; // 执行绑定的办法 servletBinder.bind(servletRequest);}复制代码

bind

持续深刻bind办法

public void bind(ServletRequest request) { // 获取所有参数的键值对 MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues(request); // 解决文件上传申请 MultipartRequest multipartRequest = WebUtils.getNativeRequest(request, MultipartRequest.class); if (multipartRequest != null) {  bindMultipart(multipartRequest.getMultiFileMap(), mpvs); } // 把url中携带的参数也退出到MutablePropertyValues addBindValues(mpvs, request); // 执行绑定(注入值) doBind(mpvs);}复制代码

因为调用档次过深,所以无奈一步步列出上面的步骤,doBind办法的原理还是通过调用POJO对象里的setter办法设置值,能够查看最终的调试信息

依据调试信息能够看到,最终执行的还是POJO对象的setter办法,具体执行的类是BeanWrapperImpl。

理解了参数的绑定,再来看返回值的解决。

返回值解决

invokeAndHandle

回到源码invokeAndHandle办法处(ServletInvocableHandlerMethod类中),该办法定义如下

/** * Invoke the method and handle the return value through one of the * configured {@link HandlerMethodReturnValueHandler HandlerMethodReturnValueHandlers}. * @param webRequest the current request * @param mavContainer the ModelAndViewContainer for this request * @param providedArgs "given" arguments matched by type (not resolved) */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 {  // 真正解决不同类型返回值的办法  this.returnValueHandlers.handleReturnValue(    returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) {  if (logger.isTraceEnabled()) {   logger.trace(formatErrorForReturnValue(returnValue), ex);  }  throw ex; }}复制代码

真正解决不同类型的返回值的办法是handleReturnValue办法

handleReturnValue

/** * Iterate over registered {@link HandlerMethodReturnValueHandler HandlerMethodReturnValueHandlers} and invoke the one that supports it. * @throws IllegalStateException if no suitable {@link HandlerMethodReturnValueHandler} is found. */@Overridepublic 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);}复制代码

selectHandler

@Nullableprivate HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) { boolean isAsyncValue = isAsyncReturnValue(value, returnType); for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {  if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {   continue;  }  if (handler.supportsReturnType(returnType)) {   return handler;  } } return null;}复制代码

依据调试信息能够看到,SpringMVC为返回值提供了15个HandlerMethodReturnValueHandler的实现了来解决不同类型的返回值。

事实上,用来解决@ResponseBody类型的是RequestResponseBodyMethodProcessor。

如果对前文参数绑定还有印象的话,会发现@RequestBody类型参数绑定也是用的这个类。

持续跟进RequestResponseBodyMethodProcessor类的handleReturnValue办法

handleReturnValue

RequestResponseBodyMethodProcessor类的handleReturnValue办法定义如下

这里设置了一个十分重要的属性requestHandled,这个属性关系到是否须要返回ModelAndView对象
@Overridepublic void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,  ModelAndViewContainer mavContainer, NativeWebRequest webRequest)  throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { // 设置该申请是否已在处理程序中齐全解决,例如@ResponseBody办法不须要视图解析器,此处就能够设置为true。 // 当控制器办法申明类型为ServletResponse或OutputStream的参数时,也能够设置此标记为true。  // 这个属性设置成true之后,下层getModelAndView获取ModelAndView时会返回Null,因为不须要视图。 // 默认值为false mavContainer.setRequestHandled(true); ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest); // Try even with null return value. ResponseBodyAdvice could get involved. // 底层就是利用java.io.OutputStreamWriter类把返回值写到网络IO writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);}复制代码

持续深刻writeWithMessageConverters办法,一步步调试到最初,底层就是利用java.io.OutputStreamWriter类把返回值写到网络IO

因为handleReturnValue把requestHandled设置成了true,下层在调用getModelAndView办法时会返回null,示意该申请不须要视图。感兴趣的同学本人调试一下便知。

总结

本文次要从源码的浏览和调试的角度,整体的解说了SpringMVC解决申请的整个流程,并且解说了参数的绑定以及返回值的解决。置信大家看完后,联合本人的调试信息,会对SpringMVC的申请处理过程有一个更深刻的了解。

链接:https://juejin.cn/post/690348...