你知道SpringMvc是根据什么来调用接口的吗?

将军莫虑,且看此图

流程简介

  1. 请求发起:用户以接口的形式向 SpringMVC 应用程序发送请求。

  2. DispatcherServlet 拦截请求:DispatcherServlet 作为 SpringMVC 的核心组件,其功能为拦截所有到达应用程序的请求。

  3. 请求参数处理:DispatcherServlet 会解析请求参数,将它们转换为 Java 对象。

  4. 查找 Handler :简单来说是根据请求的 URL 和 HTTP 方法定位到Controller类里的具体方法,handler的概念和Controller本质上是一样的,控制器方法便是指Controller的接口方法。

  5. 处理请求:DispatcherServlet通知 HandlerAdapt 去执行控制器方法。

  6. 返回响应:处理器将处理结果封装为一个 ModelAndView 对象,其中 Model 是请求相关的数据,View 是一个视图(通常是 JSP 页面)。

  7. 视图解析:DispatcherServlet 根据 ModelAndView 中的视图名称,查找并返回对应的 JSP 页面。

以上流程中本文章将以3~5为重点进行讲解

流程详解

1.SpringMvc怎么根据请求定位到控制器方法

要解答这个问题我们得先了解一下 RequestMappingHandlerMapping以及HandlerMapping

HandlerMapping俗称处理器映射器(用来根据请求信息匹配handler),而RequestMappingHandlerMapping实现HandlerMapping,负责收集并管理所有带有@Controller注解的控制器类,以及带有@RequestMapping或者是@PostMapping之类一系列注解的控制器方法。

DispatcherServlet在执行过程中会携带着请求各种信息到RequestMappingHandlerMapping匹配到合适的控制器方法,以便后续执行。

less 复制代码
@PutMapping("/hello4")
public ModelAndView test4(@RequestParam String token){
    log.debug("test({})",token);
    return null;
}
ini 复制代码
MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/hello4");
request.setParameter("name","张三");
MockHttpServletResponse response = new MockHttpServletResponse();
HandlerExecutionChain chain = handlerMapping.getHandler(request);

这里我们创建MockHttpServletRequest对象来模拟用户请求服务。同时进入getHandler方法打上断点进行dubug。

最终我们层层深入来到 AbstractHandlerMethodMapping的lookupHandlerMethod方法,可见RequestMappingHandlerMapping底层将接口路径"/hello4"作为键匹配到对应的handler,并封装成RequestMappingInfo

最后返回的HandlerExecutionChain对象的包括了一个handler方法以及若干拦截器

2.HandlerAdapter如何调用控制器方法

ini 复制代码
MyRequestMappingHandlerAdapter handlerAdapter = context.getBean(MyRequestMappingHandlerAdapter.class);
handlerAdapter.invokeHandlerMethod(request,response,(HandlerMethod) chain.getHandler());

在找到控制器方法后,HandlerAdapter将会通过反射机制去调用。在调用之前还要解决两件事,一是做好参数解析,而是返回值处理。

首先参数解析我们来到HandlerMethodArgumentResolverComposite类中getArgumentResolver这个方法,底层将控制器方法的参数信息收集成数组,接着遍历出所有的参数解析器,直到找到支持解析此参数的参数解析器并用map记录。

less 复制代码
@PutMapping("/hello1")
public ModelAndView test1(@RequestParam String name){

此时name参数用的是@RequestParam注解,那么对应的参数解析器便是RequestParamMethodArgumentResolver。

来到RequestParamMethodArgumentResolver发现它间接实现了HandlerMethodArgumentResolver,并重写了supportsParameter方法,由代码得知RequestParamMethodArgumentResolver在解析参数时会判断参数是否加了@RequestParam注解

返回值处理器HandlerMethodReturnValueHandler流程与参数处理器相差不大这里就不作赘述

相关推荐
凤凰院凶涛QAQ8 小时前
《Java版数据结构 & 集合类剖析》Map & Set & 反射:“从哈希碰撞到红黑树转换,反射帮你扒开 HashMap 的桶数组看个究竟”
java·数据结构·算法
H.莓飛8 小时前
【数据结构】排序_OJ题(一):计数、桶与排序后的处理
java·开发语言·数据结构
wangchunyu1149 小时前
JAVA AQS与Lock实现原理(含CAS)
java·开发语言·word
w_zero_one10 小时前
算法--模拟
java·数据结构·算法
Javatutouhouduan10 小时前
阿里1658页Java面试题总结(含答案)
java·高并发·java面试·java面试题·后端开发·java程序员·java八股文
秋天的怀念_David11 小时前
算法一千零一夜 · 第十三夜 幻方,武侠世界里的数学迷宫
java·程序人生·算法
专业程序开发源11 小时前
springboot欧缇蔓月子中心管理系统82697-计算机课程设计、毕业设计
java·spring boot·后端·python·spring·django·课程设计
秋天的怀念_David11 小时前
算法一千零一夜 · 第十四夜 幻方与奇妙的二进制
java·程序人生·算法
thefool11226611 小时前
网络编程^
java
Thinker QAQ12 小时前
并发编程(十一):Shared Memory 与 Message Passing——关系与组合使用
java·python·go·并发编程·shared memory·message passing