【老王读SpringMVC-4】请求参数是如何绑定到Controller method参数对象上的?

时间:2022-02-12 01:27:48

前面我们分析了,如果我们自己要实现 spring mvc 框架的话,大致需要实现如下功能:

  • 0、将 url 与 Controller method 的对应关系进行注册
  • 1、通过请求的 url 找到 Controller method (即 url 与 Controller method 的映射)
  • 2、将请求参数进行绑定,即将入参绑定到 Controller method 的参数对象上
  • 3、执行处 Controller method (即 HandlerAdapter#handle())
  • 4、对 Controller method 的返回值进行处理
    4.1 如果正常返回的话,对返回值对象进行处理(即 ReturnValueHandler)
    包括:如果返回视图 View 的话,对视图进行渲染 (即 ViewResolver)
    4.2 如果有异常返回的话,对异常进行处理(即 @ExceptionHandler)

上一篇我们分析了根据 url 如何找到 Controller 方法,接下来,我们再看分析一下请求参数是如何绑定到 handler method 的参数对象上的?

handler method 参数绑定的入口

还是从 DispatcherServlet 出发,来看下 Spring MVC 是在哪里开始进行参数绑定的?

【老王读SpringMVC-4】请求参数是如何绑定到Controller method参数对象上的?

可以看到,DispatcherServlet#doDispatch() 的处理大体分了 6 步:
1、获取 request 对应的 HandlerExecutionChain(它包含 handler 和 interceptors)
2、获取 handler 对应的 HandlerAdapter
3、执行 handler 的前置处理: HandlerInterceptor#preHandle()
4、通过 HandlerAdapter#handle() 来执行处理程序
5、执行 handler 的后置处理:HandlerInterceptor#postHandle()
6、对返回值进行处理(包括正常返回 和 异常处理)

所以,参数绑定应该是在执行 handler method 的时候,即 HandlerAdapter#handler()

  • 为什么需要获取 HandlerAdapter 之后,通过 HandlerAdapter#handler() 来执行 handler method 呢?
    答: 因为 Spring MVC 支持多种 handler,比如:@RequestMapping 定义的 handler method、通过 org.springframework.web.servlet.mvc.Controller 接口定义的 handler method、servlet 方式定义的 handler method等。
    为了让这些不同种类的 handler method 可以通过统一的方式进行调用执行,Spring MVC 抽象出了 HandlerAdapter 接口来统一处理客户端的 request 请求。

RequestMappingHandlerAdapter

SpringMVC 中最常用的是 @RequestMapping 标记 handler method。
@RequestMapping 标记的 HandlerMethod 对应的 HandlerAdapter 是 RequestMappingHandlerAdapter

RequestMappingHandlerAdapter#handle() 具体的调用过程如下:
【老王读SpringMVC-4】请求参数是如何绑定到Controller method参数对象上的?

可以看到,参数解析、handler method 的执行 和 对返回值的处理,最终是通过 ServletInvocableHandlerMethod#invokeAndHandle() 来处理的。

ServletInvocableHandlerMethod#invokeAndHandle() 的处理过程如下:
【老王读SpringMVC-4】请求参数是如何绑定到Controller method参数对象上的?

可以看到,参数的解析绑定是通过 HandlerMethodArgumentResolver 来处理的。

HandlerMethodArgumentResolver

HandlerMethodArgumentResolver 是 SpringMVC 用来将 request 中的参数解析出来赋值给 handler method 的入参的。

HandlerMethodArgumentResolver 的类图如下:(精简了一些实现类)
【老王读SpringMVC-4】请求参数是如何绑定到Controller method参数对象上的?

从上图可以看到 HandlerMethodArgumentResolver 的子类针对 Map、Model、@RequestParam、@PathVariable、@RequestBody、ServletRequest、HttpSession、TimeZone等都分别进行了解析处理。

我们重点看下对 @RequestBody 参数的处理:
@RequestBody 标记的参数,最终会通过 HttpMessageConverter#read() 来进行处理。
在 SpringBoot 环境下,默认会使用 MappingJackson2HttpMessageConverter 来处理。

小结

SpringMVC 的请求参数解析通常是通过 HandlerMethodArgumentResolver 来解析的,它会解析 request 中的参数,并赋值给 handler method 入参。
HandlerMethodArgumentResolver 的子类针对 Map、Model、@RequestParam、@PathVariable、@RequestBody、ServletRequest、HttpSession、TimeZone等都分别进行了解析处理。