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的流程分析(一)—— 整体流程概括的更多相关文章

  1. springmvc源码分析系列-请求处理流程

    接上一篇-springmvc源码分析开头片 上一节主要说了一下springmvc与struts2的作为MVC中的C(controller)控制层的一些区别及两者在作为控制层方面的一些优缺点.今天就结合 ...

  2. Duilib源码分析(六)整体流程

    在<Duilib源码分析(一)整体框架>.<Duilib源码分析(二)控件构造器—CDialogBuilder>以及<Duilib源码分析(三)XML解析器—CMarku ...

  3. SpringMVC源码分析-400异常处理流程及解决方法

    本文涉及SpringMVC异常处理体系源码分析,SpringMVC异常处理相关类的设计模式,实际工作中异常处理的实践. 问题场景 假设我们的SpringMVC应用中有如下控制器: 代码示例-1 @Re ...

  4. 104 - kube-scheduler源码分析 - predicate整体流程

    (注:从微信公众:CloudGeek复制过来,格式略微错乱,更好阅读体验请移步公众号,二维码在文末) 今天我们来跟一下predicates的整个过程:predicate这个词应该是“断言.断定”的意思 ...

  5. SpringMVC源码分析和启动流程

    https://yq.aliyun.com/articles/707995 在Spring的web容器启动时会去读取web.xml文件,相关启动顺序为:<context-param> -- ...

  6. OA流程分析

    OA流程分析: 1. 流程定义:可视化可拖拽的流程环节设置,流程定义完成后保存在数据表中,字段有流程ID,名称,流程流转环节. 2. 画业务表单,新建业务数据表. 3. 表单数据填好后,启动流程:

  7. Android8.1 开关VOLTE流程分析

    前言 最近有需求需要实现插卡默认打开Volte功能,顺带研究了下Volte的流程,在此做个记录 开始 从Settings设置界面入手,网络和互联网-->移动网络-->VoLTE高清通话(电 ...

  8. 阶段5 3.微服务项目【学成在线】_day17 用户认证 Zuul_01-用户认证-用户认证流程分析

    1 用户认证 1.1 用户认证流程分析 用户认证流程如下: 访问下面的资源需要携带身份令牌和jwt令牌,客户端可以通过身份认证的令牌从服务端拿到长令牌, 一会要实现认证服务请求用户中心从数据库内来查询 ...

  9. HDFS源码分析DataXceiver之整体流程

    在<HDFS源码分析之DataXceiverServer>一文中,我们了解到在DataNode中,有一个后台工作的线程DataXceiverServer.它被用于接收来自客户端或其他数据节 ...

随机推荐

  1. org.springframework.core.NestedIOException: ASM ClassReader failed to parse class file - probably du

    如果出现类似下面的错误,原因就是JDK版本太高了,我换成1.7就没事了 Caused by: org.springframework.core.NestedIOException: ASM Class ...

  2. Activiti第二篇【管理流程定义、执行任务和流程实例、流程变量】

    上篇Activiti只是一个快速入门案例,这篇就讲定义.部署.查看任务等等的一些细节[涉及到的数据库表.对象等等]- 管理流程定义 管理流程定义主要涉及到以下的4张表: -- 流程部署相关的表 SEL ...

  3. JDBC在javaweb中的应用之分页数据查询

    分页查询 分页查询是java web开发中经常使用到的技术.在数据库中数据量非常大的情况下,不适合将所有的数据全部显示到一个页面中,同时为了节约程序以及数据库的资源,就需要对数据进行分页查询操作. 通 ...

  4. PHP防SQL注入攻击

    PHP防SQL注入攻击 收藏 没有太多的过滤,主要是针对php和mysql的组合. 一般性的防注入,只要使用php的 addslashes 函数就可以了. 以下是一段copy来的代码: PHP代码 $ ...

  5. Servlet学习应该注意的几点

    一.Servlet生命周期(即运行过程) (1)初始阶段,调用init()方法 (2)响应客户请求阶段,调用service()方法.由service()方法根据提交方式不同执行doGet()或doPo ...

  6. 分享一个图片上传插件(TP5.0)

    效果预览图: 该插件主要功能是:可预览裁剪图片和保存原图片,执行裁剪图片后会删除 裁剪的原图片目录,以便减少空间.一.下载附件 地址:https://pan.baidu.com/s/1bpxZhM3 ...

  7. 基于React Native的移动平台研发实践分享

    转载:http://blog.csdn.net/haozhenming/article/details/72772787 本文目录: 一.React Native 已经成为了移动前端技术的趋势 二.基 ...

  8. 【POJ】3090 Visible Lattice Points(欧拉函数)

    Visible Lattice Points Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7705   Accepted: ...

  9. OpenVPN server端配置文件详细说明(转)

    本文将介绍如何配置OpenVPN服务器端的配置文件.在Windows系统中,该配置文件一般叫做server.ovpn:在Linux/BSD系统中,该配置文件一般叫做server.conf.虽然配置文件 ...

  10. [mysql]ERROR 1364 (HY000): Field 'ssl_cipher' doesn't have a default value 解决方法

    在MySQL数据库中的mysql.user表中使用insert语句添加新用户时,可能会出现以下错误: ERROR 1364 (HY000): Field 'ssl_cipher' doesn't ha ...