Spring MVC 学习笔记

1. Spring MVC核心类与接口

1.1 DispatcherServlet:前置控制器

Spring 提供的前置控制器,所有的请求都经过它来统一分发。DispatcherServlet 将请求分发给 Spring Controller 之前,需要借助于 Spring 提供的 HandlerMapping 定位到具体的 Controller
DispatcherServlet 也是间接最高继承了 HttpServlet.

1.2 HandlerMapping 接口:处理请求的映射

HandlerMapping 接口的实现类:

  • SimpleUrlHandlerMapping通过配置文件,把一个 URL 映射到 Controller 类上;
  • DefaultAnnotationHandlerMapping通过注解,例如 @RequestMapping,把一个 URL 映射到 Controller 类上;

1.3 HandlerAdapter 接口:处理请求的映射

Spring MVC 通过 HandlerAdapter 来实际调用处理函数。

例如:
AnnotationMethodHandlerAdapter:DispatcherServlet 中根据 HandlerMapping 找到对应的 Handler Method 后,首先检查当前工程中注册的所有可用的 HandlerAdapter,根据 HandlerAdapter 中的 supports() 方法找到可以使用的 HandlerAdapter
通过调用 HandlerAdapter 中的 handle() 方法来处理及准备 Handler Method 中的参数及 annotation (这就是 Spring MVC 如何将 Reqeust中的参数变成 Handler Method 中的输入参数的地方),最终调用实际的 Handler Method。
接口定义如下:

public interface HandlerAdapter {
    boolean supports(Object var1);

    @Nullable
    ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;

    long getLastModified(HttpServletRequest var1, Object var2);
}

1.4 Controller接口:控制器

由于我们使用了 @Controller 注解,添加了 @Controller 注解的类就可以担任控制器(Action)的职责,所以我们并没有用到这个接口。

需要为并发用户处理请求,因此实现 Controller 接口时,必须保证线程安全并可重用。
一旦 Controller 处理完用户请求,则返回 ModelAndView 对象给 DispatcherServlet 前置控制器,ModelAndView 中包含了模型(Model)和视图(View)。

  • 从宏观角度考虑,DispatcherServlet 是整个 Web 应用的控制器;
  • 从微观考虑,Controller 是单个 Http 请求处理过程中的控制器;
  • ModelAndView 是 HTTP 请求过程中返回的模型(Model)和视图(View)。

1.5 HandlerInterceptor 接口:拦截器

1.6 ViewResolver 接口的实现类

Spring 提供的视图解析器(ViewResolver)在 Web 应用中查找 View 对象,从而将相应结果渲染给客户。
不同种类的 View 会对应不同的 ViewResolver,例如:

  • JSP 需要用到 org.springframework.web.servlet.view.InternalResourceViewResolver
  • 模板引擎需要用到 org.springframework.web.servlet.view.tiles3.TilesViewResolver
  • 文件下载需要用到 org.springframework.web.servlet.view.BeanNameViewResolver

1.7 View 接口

View 也会有不同的实现类,例如返回 JSP 的 View 时需要用到 org.springframework.web.servlet.view.JstlView

1.8 LocalResolver 接口

1.9 HandlerExceptionResolver 接口:异常处理

1.10 ModelAndView 类

2. Spring 启动过程

对于一个 Web 应用,其部署在 Web 容器中(例如 Tomcat),Web 容器提供其一个全局的上下文环境,这个上下文就是 ServletContext其为后面的 Spring IoC 容器提供宿主环境。

在应用 web.xml 中会提供有 ContextLoaderListener,例如:

<!--监听器-->
<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

在 Web 容器(例如 Tomcat)启动时,会触发容器初始化事件,此时 ContextLoaderListener 会监听到这个事件,其 contextInitialized 方法会被调用,在这个方法中,Spring 会初始化一个启动上下文,这个上下文被称为根上下文,即 WebApplicationContext,这是一个接口类,确切的说,其实际的实现类是 XmlWebApplicationContext这个就是 Spring的 IoC 容器,其对应的 Bean 定义的配置由 web.xml 中的 context-param 标签指定。

public void contextInitialized(ServletContextEvent event) {
    this.initWebApplicationContext(event.getServletContext());
}

ContextLoaderListener 监听器初始化完毕后,开始初始化 web.xml 中配置的 Servlet,这个 Servlet 可以配置多个,以最常见的DispatcherServlet为例,这个 Servlet 实际上是一个标准的前端控制器,用以转发、匹配、处理每个 Servlet 请求。

DispatcherServlet 上下文在初始化的时候会建立自己的 IoC 上下文,用以持有 Spring MVC 相关的 Bean。在建立 DispatcherServlet 自己的 IoC 上下文时,会先从 ServletContext 中获取之前的根上下文(WebApplicationContext)作为自己上下文的 parent 上下文。有了这个 parent 上下文之后,再初始化自己持有的上下文。

当 Web 项目启动时,做初始化工作,所以我们大部分是配置在 web.xml 里面:

<web-app>

  <display-name>Web Application</display-name>

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext-*.xml</param-value>
  </context-param>

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  
  <filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>utf-8</param-value>
    </init-param>
  </filter>

  <filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <servlet>
    <servlet-name>springMVC_rest</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
    <servlet-name>springMVC_rest</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

</web-app>

图片引用自 https://www.jianshu.com/p/dc64d02e49ac

Web应用部署初始化流程图

图片引用自 https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc

image

3. DispatcherServlet 初始化过程

DispatcherServlet 继承了 FrameworkServletFrameworkServlet 继承了 HttpServletBeanHttpServletBean 继承了 HttpServlet 类。

第一步:HttpServletBean 类init() 方法

HttpServletBean 类有一个入口点就是重写了 init 方法。

  • 先通过 PropertyValues 获取 web.xml 文件 init-param 的参数值;
  • 然后通过 ResourceLoader 读取 .xml 配置信息;
  • BeanWrapper 对配置的标签进行解析和将系统默认的 bean 的各种属性设置到对应的 bean 属性;

第二步:FrameworkServlet 类 initServletBean() 方法

initWebApplicationContext() 初始化上下文,并作为值放到了 ServletContext 里,因为不同的 DispatherServlet 有对应的各自的上下文,而且上下文有设置父上下文和 id 属性等。
上下文项目启动时会调用 createWebApplicationContext() 方法。

第三步:DispatcherServlet 类 onRefresh() 方法

DispatcherServlet 初始化各个功能的实现类。比如异常处理、视图处理、请求映射处理等。

// 初始化上传文件解析器
initMultipartResolver(context);
// 初始化本地解析器
initLocaleResolver(context);
// 初始化主题解析器
initThemeResolver(context);
// 初始化映射处理器
initHandlerMappings(context);
// 初始化适配器处理器
initHandlerAdapters(context);
// 初始化异常处理器
initHandlerExceptionResolvers(context);
// 初始化请求到视图名翻译器
initRequestToViewNameTranslator(context);
// 初始化视图解析器
initViewResolvers(context);

4. DispatcherServlet 处理请求过程

图片引用自 https://terasolunaorg.github.io/guideline/5.0.0.RELEASE/en/Overview/SpringMVCOverview.html

image

  • 用户向服务器发送请求,请求被 Spring 前置控制 Servelt DispatcherServlet 捕获;
  • DispatcherServlet 对请求 URL 进行解析,得到请求资源标识符(URI)。然后根据该 URI,调用 HandlerMapping 获得该 Handler 配置的所有相关的对象(包括 Handler 对象以及 Handler 对象对应的拦截器),最后以 HandlerExecutionChain 对象的形式返回;
  • DispatcherServlet 根据请求获得 Handler,选择一个合适的 HandlerAdapter。(如果成功获得 HandlerAdapter 后,此时将开始执行拦截器的 preHandler(...) 方法)
  • 提取 Request 中的模型数据,填充 Handler 入参,开始执行 Handler(Controller)。 在填充 Handler 的入参过程中,根据你的配置,Spring 将帮你做一些额外的工作:
    • HttpMessageConveter:将请求消息(如 JSON、XML 等数据)转换成一个对象,将对象转换为指定的响应信息;
    • 数据转换:对请求消息进行数据转换。如 String 转换成 IntegerDouble 等;
    • 数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等;
    • 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到 BindingResultError 中;
  • Handler 执行完成后,向 DispatcherServlet 返回一个 ModelAndView 对象;
  • 根据返回的 ModelAndView,选择一个适合的 ViewResolver 返回给 DispatcherServlet
  • ViewResolver 结合 ModelView,来渲染视图;
  • 将渲染结果返回给客户端;

引用:
WEB请求处理五:MVC框架请求处理
spring 启动过程

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容

  • 学习资料源:慕课网 - Spring MVC起步 内容概要 一、前端控制器(Front Controller) 二...
    拾壹北阅读 1,958评论 0 22
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,773评论 6 342
  • 1、Spring MVC请求流程 (1)初始化:(对DispatcherServlet和ContextLoderL...
    拾壹北阅读 1,946评论 0 12
  • 领略过电梯惊魂后,我在项目选择上更为谨慎,毕竟儿子还小,太刺激的项目是不合适的。所以,所有疯狂的过山车都不考虑了!...
    阳光小同阅读 265评论 0 0