目录
- 一、常用组件:
- 1、DispatcherServlet
- 2、HandlerMapping
- 3、Handler
- 4、HandlerAdapter:
- 5、ViewResolver
- 6、View
- 二、SpringMVC的执行流程:
- 1、流程图
- 在这里插入图片描述
- 2、文字解析流程图
- 3、ContextLoaderListener
- 三、源码跟踪
- 1、doService()方法
- 2、doDispatch()方法逻辑分解
- 2.1 初始化变量
- 2.2 检查是否为文件上传等多部分请求
- 2.3 获取处理器
- 2.4 获取处理器适配器
- 2.5 处理 Last-Modified 头部
- 2.6 执行处理器前的拦截器
- 2.7 执行处理器逻辑
- 2.8 处理异步请求
- 2.9 应用默认视图名称
- 2.10 执行处理器后的拦截器
- 2.11 处理异常
- 2.12 处理分发结果
- 2.13 清理资源
- 2.14 请求处理阶段如何异常处理?
一、常用组件:
1、DispatcherServlet
- 前端控制器,不需要工程师开发,由框架提供.
- 作用:统一处理请求和响应,整个流程的控制中心,由他调用其它组件处理用户的请求
2、HandlerMapping
- 处理映射器,不需要工程师开发,由框架提供
- 作用:根据请求的url,method等信息查找Handler,即控制器方法
3、Handler
- 处理器,需要工程师开发
- 作用:在DispatcherServlet的控制器Handler对具体的用户请求进行处理
4、HandlerAdapter:
- 处理适配器,不需要供货才能是开发,由框架提供
- 作用:通过HandlerAdapter催处理器进行执行
5、ViewResolver
- 视图解析器,不需要工程师开发,由框架提供
- 作用:进行视图解析,得到响应的视图,如:ThymeleafView,InternalResourceView,RedirectView
6、View
- 视图:简单理解就是可视化界面
- 作用:将模型数据通过页面展示给用户
二、SpringMVC的执行流程:
1、流程图
2、文字解析流程图
以下流程的代码DispatcherServlet
的doService
方法中调用的doDispatch
方法中找到。
- 用户向服务器发送请求,请求被SpringMVC前端控制器DispatcherServlet捕获。
- 为啥请求能被
DispatcherServlet
捕获?- 因为
DispatcherServlet
间接继承了HttpServlet
。
- 因为
- 为啥请求能被
DispatcherServlet
对请求URL进行解析,得到请求资源标识符(URL),判断请求URL对应的映射:- 不存在:
- 再判断是否配置了
mvc:default-servlet-handler
- 如果没设置,则控制台包映射查找不到,客户端展示404错误
- 再判断是否配置了
- 存在:
- 根据该URL,调用
HandlerMapping
获得该Handler配置的所有先关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain
执行链对象的形式返回 DispatcherServlet
根据获得的Handler,选择一个合适的HandlerAdapter
- 如果成果获得
HandlerAdapter
,测试将开始执行拦截器的preHander(…)
方法[正向] - 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)方法,处理请求,在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
HttpMessageConveter
:将请求消息,转换成一个对象,将对象转换为指定的响应信息- 数据转换:对请求信息进行数据转换,如String转换成Integer,Double等
- 数据格式化:对请求消息进行格式化,如将字符串准换成格式化数字或格式化日期等
- 数据验证:验证数据的有效性(长度,格式等),验证结果存储到BindingResult或Error中
- 根据该URL,调用
- Handler执行完毕后,向DispatcherServlet 返回一个ModelAndView对象
- 此时将开始执行拦截器的postHandle(…)方法[逆向]
- 根据返回的
ModelAndView
(此时会判断是否存在异常:如果存在异常,则执行HandlerExceptionResover
进行异常处理)选择一个适合的ViewResolver
进行视图解析,根据Model和View,来渲染视图。 - 渲染视图完毕执行拦截器的
afterCompletion(…)
方法[逆向] - 将渲染视图结果返回给客户端.
3、ContextLoaderListener
- Spring提供了监听器
ContextLoaderListener
,实现ServeltContextListener
接口,可监听ServletContext的状态,在web服务器的启动,读取Spring的配置文件,创建Spring的IOC容器,web应用中不许在web.xml中配置.
<listener>
//配置Spring的监听器,在服务启动时加载Spring的配置文件,Spring配置文件默认位置和名称:/WEB-INF/applicationContext.xml,通过上下文参数自动以Spring配置文件的位置和名称
<listener-class>org.springframework.web.context.ContextLoaderListener<listenern-class>
</listener>
三、源码跟踪
1、doService()方法
一切请求始于DispatcherServlet的doService()方法。
@Overrideprotected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {//logRequest 方法通常用于记录请求相关信息。logRequest(request);// 使SpringMVC能处理程序和视图对象可用。request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());if (this.flashMapManager != null) {FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);if (inputFlashMap != null) {request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));}request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);}try {//doDispatch 方法是 Spring MVC 请求处理的核心逻辑,涵盖了从请求解析到响应生成的完整流程。doDispatch(request, response);}finally {if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {// 如果包含,就恢复原始属性快照。if (attributesSnapshot != null) {restoreAttributesAfterInclude(request, attributesSnapshot);}}}}
2、doDispatch()方法逻辑分解
doDispatch 是 Spring MVC 框架中的核心方法,用于处理 HTTP 请求并将其分发到相应的处理器(Handler)。它是 DispatcherServlet 的关键部分,负责协调请求的整个生命周期,包括请求解析、处理器选择、视图渲染和异常处理。
2.1 初始化变量
定义了多个变量,如 processedRequest、mappedHandler、multipartRequestParsed 等,用于存储请求处理过程中的中间状态。
获取 WebAsyncManager 实例,用于管理异步请求
HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null;boolean multipartRequestParsed = false;WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);try {ModelAndView mv = null;Exception dispatchException = null;
2.2 检查是否为文件上传等多部分请求
调用 checkMultipart 方法检查请求是否包含文件上传等多部分数据。如果是,则返回一个新的封装请求对象。
processedRequest = checkMultipart(request);multipartRequestParsed = (processedRequest != request);
2.3 获取处理器
调用 getHandler
方法根据请求找到对应的处理器(Handler)
。如果没有找到处理器,则调用 noHandlerFound
方法返回 404 错误。
mappedHandler = getHandler(processedRequest);if (mappedHandler == null) {noHandlerFound(processedRequest, response);return;}
里面通过处理映射器handlerMappings
来获取Handler.最终返回一个执行链HandlerExecutionChain
。
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {if (this.handlerMappings != null) {for (HandlerMapping mapping : this.handlerMappings) {HandlerExecutionChain handler = mapping.getHandler(request);if (handler != null) {return handler;}}}return null;}
2.4 获取处理器适配器
根据处理器类型获取对应的处理器适配器(HandlerAdapter),用于执行处理器逻辑。
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
2.5 处理 Last-Modified 头部
检查请求是否可以被缓存(通过 Last-Modified 和 If-Modified-Since 头部判断)。
如果缓存命中,则直接返回 304 响应。
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {return;}
2.6 执行处理器前的拦截器
调用拦截器链的 preHandle 方法,允许拦截器在处理器执行前进行预处理。
如果拦截器返回 false,则终止请求处理。
if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}
2.7 执行处理器逻辑
调用处理器适配器的 handle 方法执行实际的业务逻辑,并返回一个 ModelAndView 对象。
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
2.8 处理异步请求
如果请求是异步的,则直接返回,后续由异步机制继续处理。
if (asyncManager.isConcurrentHandlingStarted()) {return;}
2.9 应用默认视图名称
如果 ModelAndView 中没有指定视图名称,则应用默认视图名称。
applyDefaultViewName(processedRequest, mv);
2.10 执行处理器后的拦截器
调用拦截器链的 postHandle 方法,在处理器执行后进行后处理。
mappedHandler.applyPostHandle(processedRequest, response, mv);
2.11 处理异常
如果在请求处理过程中抛出异常,则捕获并记录异常信息。
如果是普通异常,则直接捕获;如果是严重错误(如 Throwable),则包装为 NestedServletException。
catch (Exception ex) {dispatchException = ex;}catch (Throwable err) {// As of 4.3, we're processing Errors thrown from handler methods as well,// making them available for @ExceptionHandler methods and other scenarios.dispatchException = new NestedServletException("Handler dispatch failed", err);}
2.12 处理分发结果
调用 processDispatchResult 方法处理分发结果,包括渲染视图或返回响应。
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
2.13 清理资源
如果请求是多部分请求,则调用 cleanupMultipart 方法清理相关资源。
如果是异步请求,则调用 applyAfterConcurrentHandlingStarted 方法处理异步逻辑。
finally {if (asyncManager.isConcurrentHandlingStarted()) {// 代替postHandle和afterCompletionif (mappedHandler != null) {mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);}}else {// 清理多部分请求使用的任何资源.if (multipartRequestParsed) {cleanupMultipart(processedRequest);}}}
2.14 请求处理阶段如何异常处理?
- 在请求处理的每个阶段都可能抛出异常,doDispatch 方法通过多层 try-catch 结构捕获并处理这些异常。
- 异常处理逻辑包括:
- 触发 afterCompletion 方法,通知拦截器请求已完成。
- 清理多部分请求资源。
- 返回适当的错误响应。
结束
文章结束,喜欢就给个一键三连吧,你的肯定是我最大的动力,点赞上一千我就是脑瘫也出下章。