通过Http传递参数一般有两种方式,一种是通过url解析参数,一种是通过body来解决,那么我们本次说的RequestBody就是去解析请求体然后映射到我们的参数,那 么它该如何解析body呢?这就是本篇博客诞生的目的。
这个其实是SpringMVC中做的一个处理机制,在整个SpringMVC的处理流程中,会通过HandlerMethod来代理每个Map后的controller和method,在通过反射invoke method的过程中,会解析request来获得arguments,而@RequestBody就是在解析参数的这个过程中起作用的
壹. 执行流程
在InvocableHandlerMethod#getMethodArgumentValues
中,它会遍历当前HandlerMethod的参数,对于每一个参数,它都会通过HandlerMethodArgumentResolverComposite#supportsParameter
来判断是否可以被解析器解析,如果可以被解析,则通过HandlerMethodArgumentResolverComposite#resolveArguement
进行解析
对于@RequestBody来说,它对应的解析器是RequestResponseBodyMethodProcessor
,那么,我们就深入到它的源码中来一探究竟:
1 | public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor { |
贰. 注册流程
那么RequestResponseBodyMethodProcessor
是如何被注册到resolver中呢?主要是在RequestMappingHandlerAdapter
中:
RequestMappingHandlerAdapter
实现了HandlerAdapter
这个接口,这个接口是MVC框架的SPI,DispatcherServlet
通过此接口访问所有已安装的处理程序。HandlerAdapter主要是路由之后方法的适配器,DispatcherServlet在路由之后通过HandlerAdapter来执行真实的操作(handlerAdapter是通过HandlerMethod来执行的)
对于RequestResponseBodyMethodProcessor
来说,它实现了InitializingBean
,在bean初始化之后会添加参数处理器和返回值处理器,对于参数处理器来说,内容如下:
从图中我们可以看到,RequestMappingHandlerAdapter
在初始化的时候会把系统给定的,自定义的参数解析器加载到内存中。
加入说,我们要自定义一个参数解析器,系统会在什么时候加载进入内存呢?
我们发现RequestMappingHandlerAdapter#setCustomArgumentResolvers
这个方法就是要去设置自定义参数解析器的,那么我们只需要找到它的调用方即可。
我们只需要实现WebMvcConfigurer即可(这点关系到Spring的自动装配,暂时没有看到,先鸽一下)
叁. 设计优点
设计模式
采用策略模式+工厂模式 + 组合模式:
对于HandlerMethod的参数和返回值处理来说,对应着不同的处理方式,即对应着不同的策略,所以此处用的策略模式来处理的。至于HandlerMethodArgumentResolverComposite
它则对应着策略工厂,同时,因为这个类实现了HandlerMethodArgumentResolver
,所以它也是组合模式的变形,具体的策略类是HandlerMethodArgumentResolver
类图如下:
缓存处理
在参数解析工厂中,刚开始的参数解析器是在刚启动时注册到list中,但是如果之后被使用的时候就会存放到map中,可以直接获得(key是MethodParam),提高路由效率
附:常见的MVC参数注解
对于url解析参数来说,有两个注解,分别是pathVariable
(指一种占位符)和requestParam
,对于body来说,有requestBody
。不加注解,也可以直接把url转为对应参数或者实体类
- @PathVariable: www.666.com/web/6
1 |
|
- @ReqeustParam: www.666.com/web?user=1
1 |
|
- @RequestBody: www.666.com/web body中是json
1 |
|
1 |
|