SpringMVC的流程分析(一)—— 整体流程概括
SpringMVC的整体概括
之前也写过springmvc的流程分析,只是当时理解的还不透彻所以那篇文章就放弃了,现在比之前好了些,想着写下来分享下,也能增强记忆,也希望可以帮助到别人,如果文章中有什么错误的地方欢迎各位指出。(本文针对有一定的springmvc使用经验的it人员)。
1.springmvc存在的意义
任何一个框架都有其存在的价值,可以或多或少帮助我们解决一个繁琐的问题,springmvc也不例外,说白了其实他也没啥了不起,他就是个彻头彻尾的Servlet,
一个封装许多任务的servlet,正是这些封装我们才感觉不到他单单是个servlet,因为他太厉害了,每个人在使用的时候应该都有过配置web.xml的经验,其中可以清晰的看到springmvc的配置,如下:
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/spring/spring-servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
我们可以看到springmvc的配置就是一个servlet的配置,对所有的url进行拦截。所以我们可以总结springmvc的作用:作为一个总的servlet对客户端的请求进行分发,然后对不同的请求处理,并返回相应的数据。
2.springmvc的设计类图

3.springmvc的入口
上图中黄色标识的DispatcherServlet就是sprigmvc请求的核心入口类,可以看到这类通过FrameworkServelt间接继承了HttpServletBean,FrameworkServelt实现了ApplicationContextAware,用来设置springmvc的全局上下文,当客户发送请求时会先进入DispatcherServlet的doService方法:
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
//省略不重要代码。。。
try {
this.doDispatch(request, response);
} finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot1 != null) {
this.restoreAttributesAfterInclude(request, attributesSnapshot1);
}
}
}
其实是调用了doDispatch方法,这个方法十分重要,基本上对请求的所有处理都是在这个方法中完成的:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView err = null;
Exception dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
this.noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ex = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ex.getLastModified(request, mappedHandler.getHandler());
if (this.logger.isDebugEnabled()) {
this.logger.debug(
"Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
err = ex.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(request, err);
mappedHandler.applyPostHandle(processedRequest, response, err);
} catch (Exception arg18) {
dispatchException = arg18;
}
this.processDispatchResult(processedRequest, response, mappedHandler, err, dispatchException);
} catch (Exception arg19) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, arg19);
} catch (Error arg20) {
this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, arg20);
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
首先一上来是检查是否是文件上传请求,(这个检查的目的是为了在finally中清除文件上传相应的信息),然后就是获取handler
mappedHandler = this.getHandler(processedRequest);
什么是handler呢?其实handler是springmvc自己定义的一个处理具体请求的不同类的总称,我们知道客户端的请求有很多类型,例如静态资源的请求,动态资源的请求,restful风格的请求,也可能有原始servlet类型的请求,这些处理类的总称就是handler,具体如何得到handler我会另起一个章节讲解。好了,得到了hander(处理请求类)后我们是不是可以直接来处理请求了呢,就像这样:
handler.methodname(request,response);
其实还真是这样,哈哈,肯定是这样的呀,不过人家springmvc的设计者比咱们高明多了,才不会这么lou的写,好了,我们看看他们是怎么高明的吧:
HandlerAdapter ex = this.getHandlerAdapter(mappedHandler.getHandler());
HandlerAdapter?这是什么鬼呀,怎么得到了handler怎么还在得到HandlerAdapter呢,其实这就是人家的高明之处了,这里使用了适配器设计模式,每一种handler都会有一个对应的适配器,这样子我们就不用每次都判断handler的类型,然后调用不同的方法了,举个例子:
class Handler1{
Object handle1(HttpRequest request,HttpResponse response){
}
}
class Handler2{
Object handle2(HttpRequest request,HttpResponse response){
}
}
class Handler3{
Object handle3(HttpRequest request,HttpResponse response){
}
}
这里有3个处理类,正常我们的调用是这样的:
if (handle instanceof Handler1) {
handle.handle1();
}
if (handle instanceof Handler2) {
handle.handle2();
}
if (handle instanceof Handler3) {
handle.handle3();
}
如果我们此时又多了一个Handler4怎么办,难道们需要更改Springmvc的源代码吗,这显然不符合代码设计的开闭原则,适配器模式就是解决这个问题的最好方式每一个处理器都要有一个对应的适配器,这样我们就可以不用更改源代码也能添加handler了。
接下来我们看到
err = ex.handle(processedRequest, response, mappedHandler.getHandler());
这个方法是请求的最终执行,不同类型的handler会有不同的实现,当处理器处理完各自的逻辑后都会放回一个ModelAndView参数,ModelAndView是springmvc对处理器返回的结果的抽象,不论处理器实际返回的是什么,Springmvc都会讲他包装成为ModelAndView,然后对ModelAndView进行处理,这里很有意思,也给我们一种启发,如果我们会得到很多不同的结果,我们可以将它抽象为一个统一的类型数据,然后针对这个类型的数据进行统一的处理,这样我们就可以不用针对每种情况后处理了。
最后,Spingmvc会对ModelAndView进行处理,然后返回给浏览器。
this.processDispatchResult(processedRequest, response, mappedHandler, err, dispatchException); 上面这个方法就是对ModelAndView的处理。至此,springmvc的大体流程就结束了。以上只是我对springmvc的一个整体概述,之后我还会讲解Springmvc的Handler,HandlerAdapter,视图处理,拦截器,异常处理等内容。
SpringMVC的流程分析(一)—— 整体流程概括的更多相关文章
- springmvc源码分析系列-请求处理流程
接上一篇-springmvc源码分析开头片 上一节主要说了一下springmvc与struts2的作为MVC中的C(controller)控制层的一些区别及两者在作为控制层方面的一些优缺点.今天就结合 ...
- Duilib源码分析(六)整体流程
在<Duilib源码分析(一)整体框架>.<Duilib源码分析(二)控件构造器—CDialogBuilder>以及<Duilib源码分析(三)XML解析器—CMarku ...
- SpringMVC源码分析-400异常处理流程及解决方法
本文涉及SpringMVC异常处理体系源码分析,SpringMVC异常处理相关类的设计模式,实际工作中异常处理的实践. 问题场景 假设我们的SpringMVC应用中有如下控制器: 代码示例-1 @Re ...
- 104 - kube-scheduler源码分析 - predicate整体流程
(注:从微信公众:CloudGeek复制过来,格式略微错乱,更好阅读体验请移步公众号,二维码在文末) 今天我们来跟一下predicates的整个过程:predicate这个词应该是“断言.断定”的意思 ...
- SpringMVC源码分析和启动流程
https://yq.aliyun.com/articles/707995 在Spring的web容器启动时会去读取web.xml文件,相关启动顺序为:<context-param> -- ...
- OA流程分析
OA流程分析: 1. 流程定义:可视化可拖拽的流程环节设置,流程定义完成后保存在数据表中,字段有流程ID,名称,流程流转环节. 2. 画业务表单,新建业务数据表. 3. 表单数据填好后,启动流程:
- Android8.1 开关VOLTE流程分析
前言 最近有需求需要实现插卡默认打开Volte功能,顺带研究了下Volte的流程,在此做个记录 开始 从Settings设置界面入手,网络和互联网-->移动网络-->VoLTE高清通话(电 ...
- 阶段5 3.微服务项目【学成在线】_day17 用户认证 Zuul_01-用户认证-用户认证流程分析
1 用户认证 1.1 用户认证流程分析 用户认证流程如下: 访问下面的资源需要携带身份令牌和jwt令牌,客户端可以通过身份认证的令牌从服务端拿到长令牌, 一会要实现认证服务请求用户中心从数据库内来查询 ...
- HDFS源码分析DataXceiver之整体流程
在<HDFS源码分析之DataXceiverServer>一文中,我们了解到在DataNode中,有一个后台工作的线程DataXceiverServer.它被用于接收来自客户端或其他数据节 ...
随机推荐
- YYHS-Floor it
题目描述 输入 输出 样例输入 5 97 样例输出 11 提示 题解 先不管p,通过列举前面几项,不难发现当i为偶数时,a[i]=a[i-1]+a[i-2],当i为奇数时,a[i]=a[i ...
- 06jQuery-05-事件
不同的浏览器绑定事件的代码都不太一样,所以我们使用jQuery来写代码的话,可以屏蔽不同浏览器之间的差异. 在jQuery中,可以使用 on 来绑定一个事件,指定事件的名称和对应的处理函数: // 获 ...
- 解决python第三方插件下载慢的方法
在CMD中输入: pip install 插件名字 --trusted-host pypi.douban.com -i http://pypi.douban.com/simple 就是更换国内源
- 关于APP分享到QQ、微信等
<script> var shares=null; var Intent=null,File=null,Uri=null,main=null; function plusRe ...
- 前端里移动端到底比pc端多哪些知识?
端里移动端到底比pc端多哪些知识,为啥面试时好多公司都问h5水平如何? 我做过几年的web前端开发,就简单谈谈自己的感受吧.首先来看看PC端和移动端在前端开发上的一些区别:(1)PC考虑的是浏览器兼容 ...
- 【个人笔记】《知了堂》MySQL中的数据类型
MySQL中的数据类型 1.整型 MySQL数据类型 含义(有符号) tinyint(m) 1个字节 范围(-128~127) smallint(m) 2个字节 范围(-32768~32767) ...
- Spring 5:以函数式方式注册 Bean
http://www.baeldung.com/spring-5-functional-beans 作者:Loredana Crusoveanu 译者:http://oopsguy.com 1.概述 ...
- 【POJ】2348 Euclid's Game(扩欧)
Description Two players, Stan and Ollie, play, starting with two natural numbers. Stan, the first pl ...
- ArcGIS RunTime SDK for Android之Features and graphics
今天是我开通博客园的第一天,希望以后可以多在博客园上分享自己的学习心得,记录自己的学习历程.最近在学习ArcGIS RunTime SDK for Android,所以第一篇随笔就从这里来吧.官网的教 ...
- 教你ASP.NET中如何防止注入攻击
你应该在程序中验证所有的不信任输入.你应该假定所有的用户输入都是非法的.用户可以在应用程序中提供表单字段,查询字串,客户端cookies和浏览器环境值比如用户代理字串和IP地址等. 弱输入校验通常为注 ...