将军莫虑,且看此图
流程简介
请求发起:用户以接口的形式向 SpringMVC
应用程序发送请求。
DispatcherServlet
拦截请求:DispatcherServlet
作为 SpringMVC
的核心组件,其功能为拦截所有到达应用程序的请求。
请求参数处理:DispatcherServlet
会解析请求参数,将它们转换为 Java 对象。
查找 Handler:简单来说是根据请求的 URL 和 HTTP 方法定位到Controller类里的具体方法,handler的概念和Controller本质上是一样的,控制器方法便是指Controller的接口方法。
处理请求:DispatcherServlet通知
HandlerAdapt
去执行控制器方法。
返回响应:处理器将处理结果封装为一个 ModelAndView
对象,其中 Model 是请求相关的数据,View 是一个视图(通常是 JSP 页面)。
视图解析:DispatcherServlet
根据 ModelAndView
中的视图名称,查找并返回对应的 JSP 页面。
以上流程中本文章将以3~5为重点进行讲解
流程详解
1.SpringMvc怎么根据请求定位到控制器方法
要解答这个问题我们得先了解一下 RequestMappingHandlerMapping
以及HandlerMapping
HandlerMapping
俗称处理器映射器(用来根据请求信息匹配handler),而RequestMappingHandlerMapping
实现HandlerMapping
,负责收集并管理所有带有@Controller
注解的控制器类,以及带有@RequestMappin
g或者是@PostMapping
之类一系列注解的控制器方法。
DispatcherServlet
在执行过程中会携带着请求各种信息到RequestMappingHandlerMapping
匹配到合适的控制器方法,以便后续执行。
@PutMapping("/hello4")
public ModelAndView test4(@RequestParam String token){
log.debug("test({})",token);
return null;
}
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如何调用控制器方法
MyRequestMappingHandlerAdapter handlerAdapter = context.getBean(MyRequestMappingHandlerAdapter.class);
handlerAdapter.invokeHandlerMethod(request,response,(HandlerMethod) chain.getHandler());
在找到控制器方法后,HandlerAdapter
将会通过反射机制去调用。在调用之前还要解决两件事,一是做好参数解析,而是返回值处理。
首先参数解析我们来到HandlerMethodArgumentResolverComposite
类中getArgumentResolver
这个方法,底层将控制器方法的参数信息收集成数组,接着遍历出所有的参数解析器,直到找到支持解析此参数的参数解析器并用map记录。
@PutMapping("/hello1")
public ModelAndView test1(@RequestParam String name){
此时name参数用的是@RequestParam
注解,那么对应的参数解析器便是RequestParamMethodArgumentResolver
。
来到RequestParamMethodArgumentResolver
发现它间接实现了HandlerMethodArgumentResolver
,并重写了supportsParameter
方法,由代码得知RequestParamMethodArgumentResolver
在解析参数时会判断参数是否加了@RequestParam
注解
返回值处理器HandlerMethodReturnValueHandler
流程与参数处理器相差不大这里就不作赘述