这个过程很长,设计的到 web 组件很多,所以需要以一个最常见的情况作为“经典情况”来简化分析过程。突破之后再在对总体流程和框架的基础上,往上面新的补充内容。为了方便我讲解,我以:
“经典情况”是:Controller 中的@RequestMapping,方法的参数贴了@RequestParam注解,返回值上贴了@ResponseBody注解
搞完“经典情况”,后续的其他 mvc 组件作者会一个一个的分析。
RequestMappingHandlerMapping(请求映射器)
功能:把请求 request 映射到 handler;根据路径匹配
对应关系:只要我们的 Controller 写的路径匹配上了请求就可以了,假设匹配上。
HandlerMethod(处理请求)
功能:具体处理请求的
对应关系:对应是 Controller 中的方法
HandlerExecutionChain(处理器链)
功能:等于“处理器” + “匹配的拦截器”
对应关系:这里就是等于:“HandlerMethod + 匹配到的拦截器MappedInterceptor
”
RequestMappingHandlerAdapter(对HandlerExecutionChain 再次包装)
记住:反正就是由RequestMappingHandlerAdapter 开始执行的就可以了。
RequestParamMethodArgumentResolver(参数解析器)
功能:专门处理
@RequestParam
注解的
对应关系:从请求 request 中解析出参数(调用 ServletRequest的 getParameterValues方法)
RequestResponseBodyMethodProcessor(返回值处理器)
功能:专门刚好处理
@ResponseBody
注解。
DispatcherServlet 的doDispatch方法的总体执行过程:
在(1)处得到 HandlerExecutionChain
,包含 HandlerMethod
和 MappedInterceptor
在(2)处得到 RequestMappingHandlerAdapter
在(3)处,执行MappedInterceptor
的 preHandle
方法
在(4)处,执行 RequestMappingHandlerAdapter
的 handler
方法
在(5)处,执行MappedInterceptor
的 postHandle
方法
RequestMappingHandlerAdapter
的总体过程继续看 RequestMappingHandlerAdapter
的 handler
方法的总体过程:
注意:执行顺序是从左到右从上到下执行的
主要就只有 3 个关键过程(上面已加粗说明):
1、按 Controller 方法的要求解析参数。用的是 RequestParamMethodArgumentResolver
2、执行 Controller 方法。
3、处理 Controller 方法的返回值。用的是 RequestResponseBodyMethodProcessor
下面简单提一下其他过程(按序号):
在(1)处,把真正的执行的组件HandlerMethod 一顿疯狂包装成ServletInvocableHandlerMethod
比如就包装了 web 数据绑定器:WebDataBinder
在(2)处,处理视图,现在都是前后端开发,不用视图技术了。作者不讲,略,自己搞。
在它的 supportsParameter
方法中,表明了支持“参数上贴了@RequestParam注解的参数”
1、 调用RequestParamMethodArgumentResolver的resolveArgument方法,
2、 会调用到RequestParamMethodArgumentResolver 的resolveName方法
3、会调用到解析文件的multipartRequest方法 和 从请求获取参数的 request.getParameterValues
方法
4、解析之后还没有结束,还需要转换成 Controller 方法需要的参数类型(略,这就是另外的小细节故事了)
截止目前:也就通过从请求中获取参数完成了 Controller 方法参数的解析,
没什么好讲的,反射调用 Controller 的方法。
在supportsReturnType方法中表明了支持的类型是方法上@ResponseBody
注解
1、会调用到RequestResponseBodyMethodProcessor 的 handleReturnValue方法
2、会调用writeWithMessageConverters方法
3、最后直接调用“消息转换器”messageConverters把“返回值写到流里面去了”
注意:既然既然写到响应流 response 里面去了,响应就结束了,后面的视图处理过程就没了。
读完全文,读者要求掌握以下组件的工作情况。(对细节不需要苛责,但是一定要能知道** 组件的功能 **
和 **组件在流程中的位置**
。