前言
在上篇文章我们讲解了Spring MVC是如何初始化的,在这篇文章中会讲到其工作流程。
工作流程
大致流程如下:
- 用户发起请求一个url到中央控制器
- 中央控制器接收到请求后调用处理器映射器以获取相应的处理器(即controller)
- 处理器映射器返回处理器的位置给中央控制器
- 中央控制器调用处理器适配器获取到指定的处理器(即controller)
- 处理器适配器把请求交给指定的处理器执行请求
- 处理器执行完业务逻辑后,返回数据和视图给处理器适配器
- 处理器适配器把数据和视图返回给中央处理器
- 中央处理器请求视图解析器进行视图解析
- 视图解析器解析相应的视图并返回给中央控制器
- 中央控制器通过view将数据和模型填充到视图中
- view渲染完视图后返回给中央控制器
- 中央控制器把结果响应给用户
注意:本文是以5.2.3版本为讲解。
步骤一:控制请求的转发
业务逻辑如下:
- 保留请求属性的快照,以便能够恢复原始属性
- 给请求体加入一些默认属性,例如:当前环境处理器、主题处理器等
- doDispatch:具体处理请求的转发
- 并发处理未开始或可能已完成并且请求进一步处理并发结果时,恢复原始快照
在这里doDispatch是我们要关注的核心方法.
步骤二:具体处理请求的转发
处理程序将通过按顺序应用servlet的handler映射来获得。HandlerAdapter将通过查询servlet安装的HandlerAdapter来获得,以找到第一个支持handler类的HandlerAdapter。
所有HTTP方法都由该方法处理。由HandlerAdapter或处理程序自己决定哪些方法是可以接受的。
业务逻辑如下:
- checkMultipart:检查是否是文件上传的请求
- getHandler:获取当前请求的 HandlerExecutionChain,该链上包含处理器及拦截器集合,如果不存在报404异常
- getHandlerAdapter:获取当前请求的处理器适配器
- 处理以last-modified请求头的请求
- applyPreHandle:应用注册拦截器的 preHandle 方法
- handle:实际上调用处理程序
- applyDefaultViewName:处理结果视图对象
- applyPostHandle:应用已注册拦截器的 postHandle 方法
- processDispatchResult:处理处理器选择和处理程序调用的结果,可以是 ModelAndView,也可以是要解析为 ModelAndView 的 Exception
- applyAfterConcurrentHandlingStarted:请求成功响应之后的方法
步骤三:获取当前请求的 HandlerExecutionChain
循环遍历我们初始化<url,controller>哈希表中找到相匹配的执行链
步骤四:查找请求的处理程序
查找请求的处理程序,如果找不到特定的处理程序,则返回默认的处理程序。
在这里有两个核心方法:
- getHandlerInternal:查找指定请求的处理程序
- getHandlerExecutionChain:为指定的处理程序构建一个 HandlerExecutionChain,包括拦截器
步骤五:获取当前请求的处理器适配器
看到这里我们应该很熟悉了,在讲解aop的时候我们也用到了supports方法,经典的适配器模式。
步骤六:应用注册拦截器的 preHandle 方法
业务逻辑如下:
- 通过getInterceptors方法获取所有的拦截器
- 循环遍历拦截器触发处理器拦截器上的afterCompletion方法回调
步骤七:实际上调用处理程序
实际调用的是AbstractHandlerMethodAdapter#handle()方法,该方法具体实现是在RequestMappingHandlerAdapter类中实现。
步骤八:使用指定的处理程序方法来处理请求
步骤九:调用方法来处理请求并返回结果视图
这个方法很长,但我们只关心下面两个核心方法:
- invokeAndHandler:反射调用方法处理请求
- getModelAndView:返回结果视图
步骤十:反射调用方法处理请求
在这里我们重点关注下invokeForRequest方法,这个方法通过请求的上下文解析参数值然后反射调用该方法。
步骤十一:解析参数及反射调用方法
业务逻辑如下:
- getMethodArgumentValues:获取当前请求的方法参数值,检查提供的参数值并回退到配置的参数解析器,结果数组将被传递到 doInvoke
- doInvoke:使用给定的参数值调用处理程序方法
步骤十二:返回结果视图
步骤十三:处理结果视图对象
步骤十四:应用已注册拦截器的 postHandle 方法
业务逻辑如下:
- 通过getInterceptors方法获取所有的拦截器
- 循环遍历拦截器触发处理器拦截器上的postHandle方法
步骤十五:处理处理器选择和处理程序调用的结果
核心业务逻辑如下:
- 如果异常非空,处理异常
- 结果视图非空,渲染给定的ModelAndView
步骤十六:按名称解析视图
核心业务逻辑如下:
- resolveViewName:解析视图名称
- reender:获取视图
步骤十七:组装视图
时序图
写在最后
好兄弟可以点赞并关注我的公众号“javaAnswer”,全部都是干货。
本文暂时没有评论,来添加一个吧(●'◡'●)