Spring核心原理分析之MVC九大组件(1)
本文节选自《Spring 5核心原理》
1 什么是Spring MVC
Spring MVC 是 Spring 提供的一个基于 MVC 设计模式的轻量级 Web 开发框架,本质上相当于 Servlet。Spring MVC 角色划分清晰,分工明细。由于 Spring MVC 本身就是 Spring 框架的一部分,可以说和 Spring 框架是无缝集成。性能方面具有先天的优越性,是当今业界最主流的 Web 开发框架,最热门的开发技能。
首先从一个由Spring提供的DispatcherServlet开始,重写了Serlvet的init()方法、service()方法和destroy()方法,SpringMVC九大组件在DispatcherServlet的init()方法中初始化,在service()方法中执行。下面,我们先来看Spring MVC九大组件的初始化。
2 SpringMVC九大组件名称解释
Spring MVC九大组件在DispatcherServlet的init()方法中初始化,下面我详细介绍一下Spring MVC九大组件的名称和作用。
| 序号 | 组件名 | 解释 |
|---|---|---|
| 1 | MultipartResolver | 用于处理多文件上传请求。 |
| 2 | LocaleResolver | 用于从请求中解析出 Locale,是i18n的基础。 |
| 3 | ThemeResolver | 用来解析样式、图片及它们所形成的显示效果的集合。 |
| 4 | HandlerMapping | 保存Url和逻辑处理的映射关系, |
| 5 | HandlerAdapter | 动态参数适配器,让固定的Servlet处理方法调用Handler来进行处理 |
| 6 | HandlerExceptionResolver | 用来处理Handler产生的异常情况的组件。 |
| 7 | RequestToViewNameTranslator | 从请求中获取ViewName |
| 8 | ViewResolvers | 主要作用是将String类型的视图名和Locale解析为View类型的视图 |
| 9 | FlashMapManager | 用于重定向时的参数传递。 |
具体详细介绍如下:
2.1 MultipartResolver
MultipartResolver是一个大家很熟悉的组件,用于处理上传请求,通过将普通的请求包装成MultipartHttpServletRequest来实现。MultipartHttpServletRequest可以通过getFile()方法直接获得文件。如果上传多个文件,还可以调用getFileMap()方法得到 Map< FileName, File> 这样的结构。MultipartResolver的作用就是封装普通的请求,使其拥有文件上传的功能。
2.2 LocaleResolver
ViewResolver组件的resolveViewName()方法需要两个参数,一个是视图名,另一个就是Locale。参数Locale是从哪来的呢?这就是LocaleResolver组件要做的事。LocaleResolver用于从请求中解析出 Locale,比如在中国Locale当然就是zh-CN,用来表示一个区域。这个组件也是i18n的基础。
2.3 ThemeResolver
从名字便可看出,ThemeResolver组件是用来解析主题的。主题就是样式、图片及它们所形成的显示效果的集合。Spring MVC中一套主题对应一个properties文件,里面存放着与当前主题相关的所有资源,如图片、CSS样式等。创建主题非常简单,只需准备好资源,然后新建一个“主题名.properties”并将资源设置进去,放在classpath下,之后便可以在页面中使用了。Spring MVC中与主题有关的类有ThemeResolver、ThemeSource和Theme。ThemeResolver负责从请求中解析出主题名,ThemeSource则根据主题名找到具体的主题,其抽象也就是Theme,可以通过Theme来获取主题和具体的资源。
2.4 HandlerMapping
HandlerMapping是用来查找Handler的,也就是处理器,具体的表现形式可以是类,也可以是方法。比如,标注了@RequestMapping的每个方法都可以看成一个Handler。Handler负责实际的请求处理,在请求到达后,HandlerMapping的作用便是找到请求相应的处理器Handler和Interceptor。
2.5 HandlerAdapter
从名字上看,HandlerAdapter是一个适配器。因为Spring MVC中Handler可以是任意形式的,只要能够处理请求便可。但是把请求交给Servlet的时候,由于Servlet的方法结构都是doService(HttpServletRequest req, HttpServletResponse resp)形式的,要让固定的Servlet处理方法调用Handler来进行处理,这一步工作便是HandlerAdapter要做的事。
2.6 HandlerExceptionResolver
从组件的名字上看,HandlerExceptionResolver是用来处理Handler产生的异常情况的组件。具体来说,此组件的作用是根据异常设置ModelAndView,之后交给渲染方法进行渲染,渲染方法会将ModelAndView渲染成页面。不过要注意,HandlerExceptionResolver只用于解析对请求做处理阶段产生的异常,渲染阶段的异常不归它管,这也是Spring MVC 组件设计的一大原则—分工明确、互不干涉。
2.7 RequestToViewNameTranslator
RequestToViewNameTranslator组件的作用是从请求中获取ViewName。因为ViewResolver根据ViewName查找View,但有的Handler处理完成之后,没有设置View,也没有设置ViewName,便要通过这个组件来从请求中查找ViewName。
2.8 ViewResolver
ViewResolver即视图解析器,相信大家对这个组件应该很熟悉了。通常在Spring MVC的配置文件中,都会配上一个实现类来进行视图解析。这个组件的主要作用是将String类型的视图名和Locale解析为View类型的视图,只有一个resolveViewName()方法。从方法的定义可以看出,Controller层返回的String类型的视图名viewName最终会在这里被解析成为View。View是用来渲染页面的,也就是说,它会将程序返回的参数和数据填入模板中,生成HTML文件。ViewResolver在这个过程中主要做两件大事:ViewResolver会找到渲染所用的模板(第一件大事)和所用的技术(第二件大事,其实也就是找到视图的类型,如JSP)并填入参数。默认情况下,Spring MVC会为我们自动配置一个InternalResourceViewResolver,是针对JSP类型视图的。
2.9 FlashMapManager
说到FlashMapManager组件,得先说一下FlashMap。
FlashMap用于重定向时的参数传递,比如在处理用户订单时,为了避免重复提交,可以处理完post请求后重定向到一个get请求,这个get请求可以用来显示订单详情之类的信息。这样做虽然可以规避用户重新提交订单的问题,但是在这个页面上要显示订单的信息,这些数据从哪里获取呢?因为重定向是没有传递参数这一功能的,如果不想把参数写进URL(其实也不推荐这么做,除了URL有长度限制,把参数都直接暴露也不安全),那么就可以通过FlashMap来传递。只需要在重定向之前将要传递的数据写入请求(可以通过ServletRequestAttributes.getRequest()方法获得)的属性OUTPUT_FLASH_MAP_ATTRIBUTE中,这样在重定向之后的Handler中Spring就会自动将其设置到Model中,在显示订单信息的页面上就可以直接从Model中获得数据。
FlashMapManager就是用来管理FlashMap的。
3 Spring MVC关键组件的执行流程
Spring MVC九大组件的执行在DispatcherServlet的service()方法中完成。在这里,我重点介绍几个关键组件HandlerMapping、HandlerAdapter、ViewResolver在service()方法中的执行流程,具体调用分为以下几个步骤:
1、HandlerMapping回到调用HandlerAdapter
2、HandlerAdapter会返回ModelAndView
3、ModelAndView根据用户传入参数得到ViewResolvers
4、ViewResolvers会将用户传入的参数封装为View,交给引擎进行渲染。
下面给大家分享一张Spring MVC关键组件的执行流程图,以帮助大家更好地理解:

注意:上图中有大家最熟悉的两个类:ModelAndView和View类并不属于Spring MVC九大组件之列。
4 Spring MVC优化建议
前面我们已经对Spring MVC的工作原理和源码进行了分析,在这个过程中有几个优化点。
1. Controller如果能保持单例模式,尽量使用单例模式
这样可以减小创建对象和回收对象的开销。也就是说,如果Controller的类变量和实例变量可以以方法形参声明就尽量以方法形参声明,不要以类变量和实例变量声明,这样可以避免线程安全问题。
2. 处理请求的方法中的形参务必加上@RequestParam注解
这样可以避免Spring MVC使用asm框架读取.class文件获取方法参数名。即便Spring MVC对读取出的方法参数名进行了缓存,如果能不读取.class文件当然更好。
3. 缓存URL
在阅读源码的过程中,我们发现Spring MVC并没有对处理URL的方法进行缓存,也就是说,每次都要根据请求URL去匹配Controller中的方法的URL,如果把URL和方法的关系缓存起来,会不会带来性能上的提升呢?不幸的是,负责解析URL和方法对应关系的ServletHandlerMethodResolver是一个私有的内部类,不能直接通过继承该类增强代码,必须在代码后重新编译。当然,如果将URL缓存起来,必须考虑缓存的线程安全问题。

本文为“Tom弹架构”原创,转载请注明出处。技术在于分享,我分享我快乐!
如果本文对您有帮助,欢迎关注和点赞;如果您有任何建议也可留言评论或私信,您的支持是我坚持创作的动力。
原创不易,坚持很酷,都看到这里了,小伙伴记得点赞、收藏、在看,一键三连加关注!如果你觉得内容太干,可以分享转发给朋友滋润滋润!
Spring核心原理分析之MVC九大组件(1)的更多相关文章
- 30个类手写Spring核心原理之MVC映射功能(4)
本文节选自<Spring 5核心原理> 接下来我们来完成MVC模块的功能,应该不需要再做说明.Spring MVC的入口就是从DispatcherServlet开始的,而前面的章节中已完成 ...
- Spring核心原理之IoC容器初体验(2)
本文节选自<Spring 5核心原理> 1 IoC与DI基本概念 IoC(Inversion of Control,控制反转)就是把原来代码里需要实现的对象创建.依赖,反转给容器来帮忙实现 ...
- 30个类手写Spring核心原理之环境准备(1)
本文节选自<Spring 5核心原理> 1 IDEA集成Lombok插件 1.1 安装插件 IntelliJ IDEA是一款非常优秀的集成开发工具,功能强大,而且插件众多.Lombok是开 ...
- Spring IOC原理分析
IOC IOC(Inversion of Control)控制反转:所谓的控制反转,就是把原先需要我们代码自己实现对象的创建和依赖,反转给容器来实现.那么必然Spring需要创建一个容器,同时需要创建 ...
- Spring事务原理分析-部分一
Spring事务原理分析-部分一 什么事务 事务:逻辑上的一组操作,组成这组操作的各个单元,要么全都成功,要么全都失败. 事务基本特性 ⑴ 原子性(Atomicity) 原子性是指事务包含的所有操作要 ...
- Spring事务原理分析-部分二
Spring事务原理分析-部分二 说明:这是我在蚂蚁课堂学习了余老师Spring手写框架的课程的一些笔记,部分代码代码会用到余老师的课件代码.这不是广告,是我听了之后觉得很好. 课堂链接:Spring ...
- Java Reference核心原理分析
本文转载自Java Reference核心原理分析 导语 带着问题,看源码针对性会更强一点.印象会更深刻.并且效果也会更好.所以我先卖个关子,提两个问题(没准下次跳槽时就被问到). 我们可以用Byte ...
- 30个类手写Spring核心原理之动态数据源切换(8)
本文节选自<Spring 5核心原理> 阅读本文之前,请先阅读以下内容: 30个类手写Spring核心原理之自定义ORM(上)(6) 30个类手写Spring核心原理之自定义ORM(下)( ...
- 【串线篇】SpringMVC九大组件
SpringMVC中的Servlet一共有三个层次,分别是HttpServletBean.FrameworkServlet和 DispatcherServlet. HttpServletBean直接继 ...
随机推荐
- CF1578J Just Kingdom
考虑一个点被填满则他需要从其父亲得到\(q_u = \sum_{v = u\ or\ v \in son_u}m_v\) 那么考虑如何这样操作. 我当时world final做的时候,是从上往下遍历, ...
- Educational Codeforces Round 94 题解
我竟然比到了全场的 rk 14,incredible! A 大水题,直接输出 \(n\) 遍 \(s_n\) 即可. B 分类讨论题,放在 B 题可能难度有点大了. 直接暴力枚举你拿了多少个宝剑,然后 ...
- Codeforces 796E - Exam Cheating(dp)
Codeforces 题目传送门 & 洛谷题目传送门 当被数据结构搞自闭的 tzc 信心满满地点开一道 *2400 的 dp 题时-- 却发现自己不会做?! 这足以证明蒟蒻 dp 之菜/dk/ ...
- 『学了就忘』Linux文件系统管理 — 61、使用parted命令进行分区
目录 1.parted命令介绍 2.parted交互模式 3.建立分区 (1)查看分区 (2)修改成GPT分区表 (3)建立分区 (4)建立文件系统(格式化) (5)调整分区大小 (6)删除分区 1. ...
- 2基因组间鉴定SV
本文学习费章军老师文章Genome of Solanum pimpinellifolium provides insights into structural variants during toma ...
- Excel-统一小括号格式(中文小括号,英文小括号)
1.统一小括号格式(中文小括号,英文小括号) 公式=ASC("(") #"(" 解释函数: ASC(A1)#对于双字节字符集(DBCS)语言,将全角英文字符(即 ...
- C++ 中的多重继承的问题
如何正确使用C++多重继承 BY R12F · PUBLISHED 2011年06月17日 · UPDATED 2012年03月11日 原创文章,转载请注明:转载自Soul Apogee本文链接地 ...
- 对于vue项目更新迭代导致上传至服务器后出现Loading chunk {n} failed和Unexpected token <的解决方式
相信大家对于vue项目的维护与更新中会遇见很多问题,其中有两种情况最为常见. 一种是Loading chunk {n} failed,这种情况出现的原因是vue页面更新上传至服务器后,由于vue默认打 ...
- 虚拟机中安装centos系统的详细过程
linux-centos的安装 检查电脑是否开启虚拟化,只有开启虚拟化才能安装虚拟机 新建虚拟机 鼠标点进去,选中红框所示,回车 登录: 输入默认用户名(超级管理员 root) 密码:安装时设置的密码
- Shell变量与算术运算
区分两个 Shell Shell 语言与 Shell 解释器 Shell 语言 写 Shell 脚本使用的是 Shell 语言,Shell 既是一种命令语言,又是一种程序设计语言. 作为命令语言,它交 ...