spring-mvc 请求流程学习

发布时间 2023-10-11 20:36:59作者: 冷扑星

参考:01、基础入门-SpringBoot2课程介绍_哔哩哔哩_bilibili

image-20231011172405870

请求进入HttpServlet 的doGet方法

然后通过实现类org.springframework.web.servlet.FrameworkServlet#doGet()

调用 org.springframework.web.servlet.FrameworkServlet#processRequest

----》org.springframework.web.servlet.DispatcherServlet#doService

----》org.springframework.web.servlet.DispatcherServlet#doDispatch

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
      代码1  mappedHandler = getHandler(processedRequest);
      代码2 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
        // Actually invoke the handler.
      代码3  mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    }

代码1.根据映射器获取handler

getHandler(processedRequest) 就是 请求处理器映射器获取对应的handler

@Nullable
protected 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;
}

在默认情况下springmvc 会提供5个

image-20231011174802738

如果是在controller层标注了@RequestMapping 那就是会使用

RequestMappingHandlerMapping


代码2.根据handler 获取处理器适配器

getHandlerAdapter(mappedHandler.getHandler()); 就是 请求处理器映射器获取对应的handler


代码3.执行controller层代码

ha.handle(processedRequest, response, mappedHandler.getHandler());

这里面有个前提就是springmvc如何获取请求入参 比如@PathVariable /@RequestParam

因为此时代码执行到了ha.handle(processedRequest, response, mappedHandler.getHandler());

此时的调用链是

org.springframework.web.servlet.HandlerAdapter#handle

----》org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handle

----》org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal

----》org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
                                           HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    注意点1:if (this.argumentResolvers != null) {
        invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
    }
    注意点2: if (this.returnValueHandlers != null) {
        invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
    }
    注意点3: invocableMethod.invokeAndHandle(webRequest, mavContainer);
    return getModelAndView(mavContainer, modelFactory, webRequest);
}

在上面的代码中里面有着注意点1argumentResolvers 这里面就是用来解析 对应的入参的

通过debug的形式可以发现里面的内容

image-20231011180100764

就举例PathVariableMapMethodArgumentResolver 这里面就标识了注解parameter.getParameterAnnotation(PathVariable.class);

public class PathVariableMapMethodArgumentResolver implements HandlerMethodArgumentResolver {

   @Override
   public boolean supportsParameter(MethodParameter parameter) {
      PathVariable ann = parameter.getParameterAnnotation(PathVariable.class);
      return (ann != null && Map.class.isAssignableFrom(parameter.getParameterType()) &&
            !StringUtils.hasText(ann.value()));
   }

   /**
    * Return a Map with all URI template variables or an empty map.
    */
   @Override
   public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
         NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

      @SuppressWarnings("unchecked")
      Map<String, String> uriTemplateVars =
            (Map<String, String>) webRequest.getAttribute(
                  HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);

      if (!CollectionUtils.isEmpty(uriTemplateVars)) {
         return new LinkedHashMap<>(uriTemplateVars);
      }
      else {
         return Collections.emptyMap();
      }
   }

}

然后里面还有着 注意点2返回值的returnValueHandlers

这里面的内容有着这里面的就是开头那个流程图图片里的ModeAndView对象

image-20231011180409870

接下来是 注意点3 invocableMethod.invokeAndHandle(webRequest, mavContainer);

org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle

--》org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest

--》org.springframework.web.method.support.InvocableHandlerMethod#doInvoke

这里面就是通过反射然后调用controller层代码了


针对于视图解析器上,因为普遍采用的都是前后端分离了,基本都是json数据了,所以暂时不怎么了解了