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.它被用于接收来自客户端或其他数据节 ...
随机推荐
-
MVC中的成员资格,授权,安全性
使用 Authorize 特性登录 Authorize 是 ASP.NET MVC 自带的默认授权过滤器, 可用来限制用户对操作方法的访问. 保护控制器操作 Authorize 特性在表单身份验证和 ...
-
磁盘文件系统Fat、Fat32、NTFS、exFAT的优缺点
我们在Windows系统里格式化磁盘的时候,文件系统的选项里可以看到有“FAT”.“FAT32”.“NTFS”等选项,在对U盘或其他移动存储设备 格式化的时候还会出现“exFAT”选项,那么这四种磁盘 ...
-
com.android.internal.os.ZygoteInit$MethodAndArgsCaller 解决
好久没写博客了,带着点小愧疚来,添上几个字: 这是今天遇到的一个bug,之前也遇到过,为了后面方便,就记下. bug提示:com.android.internal.os.ZygoteInit$Meth ...
-
编写出色的GNU/Linux程序
http://advancedlinuxprogramming.com提供了本书电子版的免费下载. 1 与执行环境交互 关于参数 C语言程序的main()函数使用两个参数和执行环境交互--(int)a ...
-
基本套接字编程(5) -- epoll篇
1. epoll技术 epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃 ...
-
shell脚本初识
#!/bin/bash(linux脚本环境的声明即解释器,该解释器为bash,位于根目录下的bin目录下) 变量的定义与赋值: 格式:变量名=变量值(无需声明变量类型) 变量的引用: 格式:$变量名 ...
-
Solr Dataimport配置
参考资料: https://cwiki.apache.org/confluence/display/solr/Uploading+Structured+Data+Store+Data+with+the ...
-
volley源代码解析(七)--终于目的之Response&;lt;T&;gt;
在上篇文章中,我们终于通过网络,获取到了HttpResponse对象 HttpResponse是android包里面的一个类.然后为了更高的扩展性,我们在BasicNetwork类里面看到.Volle ...
-
转载--C# PLINQ 内存列表查询优化历程
http://www.cnblogs.com/dengxi/p/5305066.html 产品中(基于ASP.NET MVC开发)需要经常对药品名称及名称拼音码进行下拉匹配及结果查询.为了加快查询的速 ...
-
[undefined,1] 和 [,1]的区别在哪里--认识js中的稀疏数组
事情是这样的 今天我想写一个能快速生成一个自然数数组的函数,就是[0,1,2,3]这样的,然后我写了下面的代码: new Array(10).map((item, index) => { ret ...