Spring MVC的请求处理逻辑
当大家了解了如何编写一个简单的Spring MVC程序后,大家心中应该会有一些好奇:这背后到底发生了什么?
Spring MVC是怎么把这些功能串联起来的?我们只是写了一个控制器而已,HTTP请求是怎么转换为控制器方法的调用的?结果又是怎么变成JSON的.....啊这小伙伴们是不是已经混乱了!?
接下来让我们看看这背后究竟发生了什么。
请求的处理流程
现代Java Web项目在处理HTTP请求时基本都遵循一样的规范,即Java Servlet规范(JSR 340)。其处理流程都是Servlet容器(例如Tomcat或Jetty)收到一个请求,接着找到合适的Servlet进行处理,随后返回响应。
在SpringMVC中,这个处理请求的Servlet就是前面提到过的DispatcherServlet。
根据配置,Servlet容器会将指定的请求都交由它来处理,在收到请求后,DispatcherServlet会在Spring容器中找到合适的处理器(大部分情况下是控制器,即带有@Controller注解的类)来处理请求,处理结果经过视图模版后得到呈现(render)的响应内容,最后再返回给用户,具体流程如下图所示:

- DispatcherServlet 接收到客户端发送的请求。
- DispatcherServlet 收到请求,调用HandlerMapping 处理器映射器
- HandleMapping 根据请求URL 找到对应的handler 以及处理器 拦截器,返回给DispatcherServlet
- DispatcherServlet 根据handler 调用HanderAdapter 处理器适配器。
- HandlerAdapter 根据handler 执行处理器,也就是我们controller层写的业务逻辑,并返回一个ModeAndView
- HandlerAdapter 返回ModeAndView 给DispatcherServlet
- DispatcherServlet 调用 ViewResolver 视图解析器来 来解析ModeAndView
- ViewResolve 解析ModeAndView 并返回真正的view 给DispatcherServlet
- DispatcherServlet 将得到的视图进行渲染,填充到request域中
- 返回给客户端响应结果。
1.DispatcherServlet的初始化
Servlet继承图

既然DispatcherServlet是一个Servlet的实现,那就会遵循其生命过程,例如会在创建后进行初始化。

HttpServletBean.init()方法调用了子类的方法FrameworkServlet.initServletBean(),其中做了Web应用上下文的初始化,用的就是initWebApplicationContext()。

在初始化Web应用上下文或者是上下文更新时,都会调用DispatcherServlet.onRefresh(),而这个方法就一句话,直接调用initStrategies(),就是在初始化Spring MVC的很多特殊类型的Bean

Spring MVC中的特殊Bean类型
| Bean类型 | 说明 |
|---|---|
| MultipartResolver | 用来解析Multipart请求的解析器,通常是上传文件的请求,MultipartResolver这层抽象的背后会有多种实现,例如基于Commons FileUpload |
| LocaleResolver | 和语言环境有关的解析器,通常用于国际化相关的场景中,包含时区、语言等多种信息 |
| ThemeResolver | 主题(Theme)解析器,选择应用程序的外观界面,主题通常是一组静态资源 |
| HandlerMapping | 用于将请求映射到处理器上,过程中还包括各种前置与后置处理,两个主要的实现类是RequestMappingHandlerMapping和SimpleUrlHandlerMapping |
| Handler Adapter | 用于触发执行处理器,通过这层抽象,DispatcherServler可以不用关心具体如何执行调用 |
| HandlerExceptionResolver | 异常处理解析器 |
| ViewResolver | 用于将字符串形式的视图名称转化为具体的View,RequestToViewNameTranslator会根据请求信息转换对应的视图名称 |
| FlashMapManager | 用于存取在请求暂存的输入与输出信息,通常会用在重定向时 |
2.请求的处理过程
DispatcherServlet在收到请求后,会交由doService()方法来进行处理,其中包含了两个主要的步骤:
- 第一步,向请求中设置Spring MVC相关的一些属性
- 第二步,调用doDispatch(request, response);将请求分派给具体的处理器执行实际的处理。
在这里说一下,DispatcherServlet用到的设计模式是委派模式
委派模式:干活算你的(普通员工),功劳算我的(一些项目经理,他们不干活!)
例如:老板(Boss)给项目经理(Leader)下达任务,项目经理会根据实际情况给每个员工派发任务,待员工把任务完成后,再由项目经理向老板汇报结果
下表是doService()方法中设置到HttpServletRequest里的几个属性:
| 属性名 | 说明 |
|---|---|
| WEB_APPLICATION_CONTEXT_ATTRIBUTE | WebApplicationContext,Web的应用上下文 |
| LOCALE_RESOLVER_ATTRIBUTE | 处理请求时可能会需要用到的LocaleResolver,如果没有国际化需求,可以忽略它 |
| THEME_RESOLVER_ATTRIBUTE | 用来决定使用哪个显示主题的ThemeResolver,如果没有这个需求,也可以忽略它 |
| THEME_SOURCE_ATTRIBUTE | 用来获取主题的ThemeSource,默认是当前的WebApplicationContext |
| INPUT_FLASH_MAP_ATTRIBUTE | 上个请求传递过来暂存到FlashMapManager里的FlashMap |
| OUTPUT_FLASH_MAP_ATTRIBUTE | 用来向后传递的FlashMap中的暂存信息 |
| FLASH_MAP_MANAGER_ATTRIBUTE | 如果当前存在FlashMapManager,则将它设置到请求里 |
doDispatch()方法的大致处理逻辑如下图,DispatcherServlet会尝试根据请求来找到合适的处理器,再通过HandlerAdapter来执行处理器的逻辑,经过前置处理、处理器处理和后置处理等多个步骤,最终返回一ModelAndView。

Request MappingHandlerAdapter是专门用来调用@RequestMapping注解标记的处理器的。在处理结果的那一步,如果有异常就处理异常,例如交给专门的HandlerExceptionResolver来处理;如果没有异常就看ModelAndView,不为空则呈现具体的视图,不存在也不用担心,因为请求可能已经处理完成了。
在调用处理器逻辑处理的过程中,针对方法的返回值,会调用HandlerMethodReturnValueHandler进行处理——根据不同的情况,会有不同实现来做处理。
例如,加了@ResponseBody的方法,返回值就直接被RequestResponseBodyMethodProcessor处理掉了,选择合适的HttpMessageConverter将对象直接序列化为相映的内容;而返回字符串作为视图名的情况,则是由ViewNameMethodReturnValueHandler来处理的。
Spring MVC的请求处理逻辑的更多相关文章
- Spring MVC 之请求处理方法可接收参数(三)
请求处理方法可接收参数 今天学习了前三个方法. 1.作用域对象2.单个表单提交数据3.表单数据封装的Bean对象 首先创建一个实体对象. package com.cy.springannotation ...
- Spring MVC文件请求处理详解:MultipartResolver
org.springframework.web.multipart.MultipartResolver是Spring-Web针对RFC1867实现的多文件上传解决策略. 1 使用场景 前端上传文件时, ...
- Spring学习之第一个Spring MVC程序(IDEA开发环境)
回顾Java平台上Web开发历程来看,从Servlet出现开始,到JSP繁盛一时,然后是Servlet+JSP时代,最后演化为现在Web开发框架盛行的时代.一般接触到一个新的Web框架,都会想问这个框 ...
- Spring MVC程序
Spring MVC程序(IDEA开发环境) 回顾Java平台上Web开发历程来看,从Servlet出现开始,到JSP繁盛一时,然后是Servlet+JSP时代,最后演化为现在Web开发框架盛行的 ...
- Spring MVC温故而知新 – 参数绑定、转发与重定向、异常处理、拦截器
请求参数绑定 当用户发送请求时,根据Spring MVC的请求处理流程,前端控制器会请求处理器映射器返回一个处理器,然后请求处理器适配器之心相应的处理器,此时处理器映射器会调用Spring Mvc 提 ...
- Spring MVC的前端控制器模式
前端控制器模式 spring mvc也是依赖servlet,所以spring mvc的请求处理是从一个servlet开始,这个servlet就是DispatcherServlet.前端控制器模式(Fr ...
- Spring MVC 学习总结(三)——请求处理方法Action详解
Spring MVC中每个控制器中可以定义多个请求处理方法,我们把这种请求处理方法简称为Action,每个请求处理方法可以有多个不同的参数,以及一个多种类型的返回结果. 一.Action参数类型 如果 ...
- Spring MVC源码分析(续)——请求处理
转自:http://blog.csdn.net/shi1122/article/details/8041017 (转移位置了,时光隧道:http://www.jmatrix.org/spring/50 ...
- Spring MVC Controller与jquery ajax请求处理json
在用 spring mvc 写应用的时候发现jquery传递的[json数组对象]参数后台接收不到,多订单的处理,ajax请求: "}]}]} $.ajax({ url : url, typ ...
- Spring MVC 请求处理流程概览
SpringMVC工作流程 图一:请求流程概述 图二:请求在每个组件的处理 解释Spring工作流程 1.用户向服务器发送请求,请求被spring前端控制Servelt DispatcherServe ...
随机推荐
- pythonn全栈学习笔记--logging模块学习(四)
一.logging相关配置 1 import logging 2 """ 3 asctime:运行时间 4 name:主模块名称 5 levelname:日志级别 INF ...
- Linux 使用Postfix与Dovecot部署邮件系统
电子邮件系统 电子邮件系统基于邮件协议来完成电子邮件的传输,常见的邮件协议有下面这些. 简单邮件传输协议(Simple Mail Transfer Protocol,SMTP):用于发送和中转发出的电 ...
- java中list对象不同属性去重合并
需求:将list中对象的不同属性对应的值去重后,赋值给另一个属性! 实现效果如下图:
- WebStore 破解
前提 你需要首先安装该软件,并下载补丁,不过这些已经为你打包好了. WebStore 2020.1 , jetbrains-agent.jar , resources_zh_CN_WebStorm_2 ...
- SpringBoot整合其他框架
SpringBoot整合Junit 实现步骤 搭建SpringBoot工程 引入starter-test起步依赖 编写测试类 添加测试相关注解 @RunWith(SpringRunner.class) ...
- QT动态库的创建和使用
QT动态库的创建和使用 步骤一: 创建一个库文件 Library 步骤二:进行动态库封装方法的实现 注意事项:要注意共享类均需要包含导出的宏定义 这个宏定义和导出向导的宏定义一致 宏定义: 向导文件: ...
- ICMP-ping报错类型
ICMP数据包的包头,两个重要字段Type和Code,如图所示 ICMP消息类型和编码类型 回显请求包,正常为80 回显回复包,正常为00 其余均为报错类型. 超时:对方主机不在线.屏蔽等 传输失败: ...
- Linux基础知识2
目录和文件管理 linux以目录形式挂载(通过目录访问存储设备)文件系统,目录结构分层的树形结构. 链接:在共享文件和访问它的用户的若干目录项之间建立联系的方法,包括硬链接和软链接两种方式 linux ...
- eset node32卸载记录
安装的是这个东西,卸载麻烦 1.一般的卸载软件比如wise program uninstall无论是普通卸载还是强制卸载都是实现不了的,火绒自带的文件粉碎是可以使用的,有两个目录要进行粉碎C:\Pro ...
- 十大经典排序之堆排序(C++实现)
堆排序 通过将无序表转化为堆,可以直接找到表中最大值或者最小值,然后将其提取出来,令剩余的记录再重建一个堆, 取出次大值或者次小值,如此反复执行就可以得到一个有序序列,此过程为堆排序. 思路: 1.创 ...