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.它被用于接收来自客户端或其他数据节 ...
随机推荐
- Jquery第三篇【AJAX 相关的API】
前言 前面我们已经学了讲解了Jquery的选择器,关于DOM 的API还有事件的API.本博文需要讲解Jquery对AJAX的支持- 我们在开始使用JavaScript学习AJAX的时候,创建异步对象 ...
- String,StringBuffer,StringBuilder的区别及其源码分析
String,StringBuffer,StringBuilder的区别这个问题几乎是面试必问的题,这里做了一些总结: 1.先来分析一下这三个类之间的关系 乍一看它们都是用于处理字符串的java类,而 ...
- 如何定制 Calico 的 IP 池?- 每天5分钟玩转 Docker 容器技术(71)
在前面的小节中,我们没有特别配置,calico 会为自动为网络分配 subnet,当然我们也可以定制. 首先定义一个 IP Pool,比如: cat << EOF | calicoctl ...
- 0 can't find referenced pointcut declarePointExpress
今天在用SpringAOP 的 @pointCut 的时候报错 Exception in thread "main" org.springframework.beans.facto ...
- node 当中的 cnpm和npm 的区别和使用
在安装nodejs之后会有npm命令 打开命令符输入之后 输入node -v(记得-v前空格)查看版本信息 如果显示出来了就说明安装成功 然后 npm 可以安装node插件 cnpm使用的是淘宝网 ...
- ①【javascript设计到的技术点】
一.dom操作: document.getElementById() document.getElementsByTagName() 二.事件操作: dom2级事件 主流浏览器 addEventLis ...
- ptyhon 编程基础之函数篇(二)-----返回函数,自定义排序函数,闭包,匿名函数
一.自定义排序函数 在Python中可以使用内置函数sorted(list)进行排序: 结果如下图所示: 但sorted也是一个高阶函数,可以接受两个参数来实现自定义排序函数,第一个参数为要排序的集合 ...
- VirtualBox安装linux mint教程
准备工作: 1.VirtualBox安装包,官方下载页面. 2.linux mint镜像iso文件,官方下载页面. 安装过程: 1.打开VirtualBox后点击新建,在弹出界面选择专家模式,类型选择 ...
- 【笔记】php常用函数
phpusleep() 函数延迟代码执行若干微秒.unpack() 函数从二进制字符串对数据进行解包.uniqid() 函数基于以微秒计的当前时间,生成一个唯一的 ID.time_sleep_unti ...
- 学习Matplotlib
介绍 Matplotlib是一个Python 2D绘图库,可以跨平台生成各种硬拷贝格式和交互式环境的出版品质量图.Matplotlib可用于Python脚本,Python和IPythonshell,j ...