1、在SpringMVC的http请求处理过程中,包括了前端控制器(DispatcherServlet)、处理映射器(HandlerMapping)、处理适配器(HandlerAdapter)、处理器((Handler)Controller)、视图解析器(ViewReslover)、视图(View)这六大主要对象。他们负责对http请求做处理,具体流程如下图。

第一步:前端控制器dispatcher接受请求

Client---url--->Dispatcher

第二步:前端控制器去发起handler映射查找请求

Dispatcher---HttpServletRequest---> HandlerMapping

第三步:处理器映射器查找hanlder并返回HandlerExetuionChain

Dispatcher <---HandlerExeutionChain---HandlerMapping

第四步:前端控制器发起请求处理器适配器请求执行

Dispatcher---Handler---> HandlerAdapter

第五步:处理器适配器去调用handler执行

HandlerAdapter---HttpServletRequest> Handler(Controller)

第六步:处理器处理后返回ModelAndView给HandlerAdapter

HandlerAdapter <---ModelAndView---Handler(Controller)

第七步:处理器适配器将ModelAndView返回给前端控制器

Dispatcher <---ModelAndView---HandlerAdapter

第八步:前端控制器请求视图解析器解析ModelAndView

Dispatcher---ModelAndView---> ViewReslover

第九步:视图解析器解析视图后返回视图View给前端控制器

Dispatcher <---View---ViewReslover

第十步:前端控制器请求视图要求渲染视图

Dispatcher--->View--->render

第十一步:前端控制器返回响应

Response <---Dispatcher

源码探秘

第一步接受请求:

我们可以来看看DispatcherServlet的继承结构

其实DispatcherServlet能处理请求是因为HttpServlet类的service方法,而HttpServlet又来自Servlet接口定义的规范。

可以看到抽象类HttpServlet实现了接口Servlet的service方法,根据请求类型不同执行了不同的方法(doGet,doPost)

当请进来后,由HttpServlet的子类FrameworkServlet重写的service方法执行请求,可以看到437行子类调用了父类的service方法,然后在父类执行doGet之类的方法时,由于子类FrameworkServlet重写了父类方法,交由子类执行,所以进到了我的doGet断点里面,它调用了处理请求方法。

接下来我们看看ProcessRequest方法的源码

 protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = this.buildLocaleContext(request);
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor(null));
this.initContextHolders(request, localeContext, requestAttributes); try {
this.doService(request, response);
} catch (IOException | ServletException var16) {
failureCause = var16;
throw var16;
} catch (Throwable var17) {
failureCause = var17;
throw new NestedServletException("Request processing failed", var17);
} finally {
this.resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
} this.logResult(request, response, (Throwable)failureCause, asyncManager);
this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
} }

前面一系列初始化工作我们先不管,看看重要的部分,try里面的doService方法

跟踪进去看了一下,由于它是抽象方法,所以会由子类实现和执行,也就是我们的DispatchServlet类了

老规矩,先贴上源码,它是DispatchServlet的doService方法--------------------------------------------------------------------------------------------------------------

 protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
this.logRequest(request);
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap();
Enumeration attrNames = request.getAttributeNames(); label95:
while(true) {
String attrName;
do {
if (!attrNames.hasMoreElements()) {
break label95;
} attrName = (String)attrNames.nextElement();
} while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet")); attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
} request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
if (this.flashMapManager != null) {
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
} request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
} try {
this.doDispatch(request, response);
} finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
this.restoreAttributesAfterInclude(request, attributesSnapshot);
} } }

所以第一步也就完成了,第一步的任务就是走进这里来。

第二步:前端控制器去发起handler映射查找请求

Dispatcher---HttpServletRequest---> HandlerMapping

上面的源码中主要工作就是给request实例设置一系列参数,要注意的就是doDispatch方法,这里面就是mvc的核心了,前面第一张交互图里面的流程都是在这里实现的。

可以看到,通过HttpRequestServlet作为参数请求handlerMapping

第三步:处理器映射器查找hanlder并返回HandlerExetuionChain

Dispatcher <---HandlerExeutionChain---HandlerMapping

可以看到上图中返回了mappedHandler变量,就是HandlerExtuceChain类型

可以看到,已经找到并返回了我们的HomeController处理器(Hanlder)

第四步:前端控制器发起请求处理器适配器请求执行

Dispatcher---Handler---> HandlerAdapter

从508行可以看到,适配器传入handler对象和reaquest等信息,执行handler()方法

第五步:处理器适配器去调用handler执行

HandlerAdapter---HttpServletRequest> Handler(Controller)

从这里可以看到,调用的handlerInternal是个抽象方法,会调用子类的实现方法,子类由RequestMappingHandlerAdapter实现,这个类也是我们经常在xml里面配置的类

通过invokeHandlerMethod方法执行进到controller里面

方法执行后返回我们的index

第六步:处理器处理后返回ModelAndView给HandlerAdapter

HandlerAdapter <---ModelAndView---Handler(Controller)

通过调用invokeHandlerMethod方法返回ModelAndView

第七步:处理器适配器将ModelAndView返回给前端控制器

Dispatcher <---ModelAndView---HandlerAdapter

第八步:前端控制器请求视图解析器解析ModelAndView

Dispatcher---ModelAndView---> ViewReslover

第九步:视图解析器解析视图后返回视图View给前端控制器

Dispatcher <---View---ViewReslover

可以看到,返回的视图,url指向index.jsp页面

第十步:前端控制器请求视图要求渲染视图

Dispatcher--->View--->render

如果View对象不为空,将会调用render方法渲染

如果返回的是json对象,属于接口的,是不会走这里的

此时会找对应的视图解析器去渲染

里面其实也没干啥,就做了个跳转,到jsp页面去绑定数据

第十一步:前端控制器返回响应

Response <---Dispatcher

到这里也就基本上完了。

处理请求完成后做了个重置工作,然后发布一个事件,你可以选择监听这个事件,做相应处理。

再看看response里面

这个就是我们页面上的内容了。

HTTP请求处理流程-SpringMvc的更多相关文章

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

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

  2. Webflux请求处理流程

    spring mvc处理流程 在了解SpringMvc的请求流程源码之后,理解WebFlux就容易的多,毕竟WebFlux处理流程是模仿Servlet另起炉灶的. 下面是spring mvc的请求处理 ...

  3. 04-SpringMVC之请求处理流程

    SpringMVC之请求处理流程 我们知道DispatcherServlet就是一个HttpServlet,而HttpServlet的请求就从doGet/doPost开始 DispatcherServ ...

  4. ASP.NET Core管道深度剖析(2):创建一个“迷你版”的管道来模拟真实管道请求处理流程

    从<ASP.NET Core管道深度剖析(1):采用管道处理HTTP请求>我们知道ASP.NET Core请求处理管道由一个服务器和一组有序的中间件组成,所以从总体设计来讲是非常简单的,但 ...

  5. ASP.Net请求处理机制初步探索之旅 - Part 5 ASP.Net MVC请求处理流程

    好听的歌 我一直觉得看一篇文章再听一首好听的歌,真是种享受.于是,我在这里嵌入一首好听的歌,当然你觉得不想听的话可以点击停止,歌曲 from 王菲 <梦中人>: --> 开篇:上一篇 ...

  6. Http 请求处理流程

    引言 我查阅过不少Asp.Net的书籍,发现大多数作者都是站在一个比较高的层次上讲解Asp.Net.他们耐心.细致地告诉你如何一步步拖放控件.设置控件属性.编写CodeBehind代码,以实现某个特定 ...

  7. Yii源码阅读笔记(二十一)——请求处理流程

    Yii2请求处理流程: 首先:项目路径/web/index.php (new yii\web\Application($config))->run();//根据配置文件创建App实例,先实例化y ...

  8. 【转载】ASP.NET页面运行机制以及请求处理流程

    本文转至 ASP.NET页面运行机制以及请求处理流程 IIS处理页面的运行机制 IIS自身是不能处理像ASPX扩展名这样的页面,只能直接请求像HTML这样的静态文件,之所以能处理ASPX这样扩展名的页 ...

  9. IIS架构与HTTP请求处理流程

    IIS架构与HTTP请求处理流程 Windows操作系统中的IIS负责提供互联网服务,一台运行了IIS的计算机可以看成是一台Web服务器. Windows XP SP2 中IIS主版本号为5,Wind ...

随机推荐

  1. 14-敌兵布阵(HDU1166线段树 & 树状数组)

    http://acm.hdu.edu.cn/showproblem.php?pid=1166 敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory ...

  2. nhibernate 3.x新特性

    http://www.360doc.com/content/14/0226/17/9316347_355904008.shtml

  3. Insufficient free space for journal files

    前两天请假了,公司的很多app突然挂掉了,说是mongodb莫名的挂掉了,赶紧进去看了看日志: --31T14:: [initandlisten] ERROR: Insufficient free s ...

  4. windows server2012安装mysql时一直停留在start server的解决方法

    安装的时候,starting server 卡住 原因分析 这个问题小编安装mysql时也碰到过,出现这个问题是my.ini文件没有复制成功了,我们只要在mysql安装目录把把目录中的备份的my-sm ...

  5. C++11中的tuple应用:让函数返回多个值

    在没有tuple之前,如果函数需要返回多个值,则必须定义一个结构体,有了C++11,可以基于tuple直接做了,下面是个示例: // 编译:g++ -std=c++11 -g -o x x.cpp # ...

  6. 跟我学习css3之transition

    HTML5和css3已经是将来的发展趋势,现在有很多移动端还有一些游戏公司已然使用它们开 发了比较成功的产品.我在2011年的时候也跟着技术潮流初浅的学习了html5+css3.毕竟那 时候我没有把学 ...

  7. [Selenium With C#基础教程] Lesson-06 单选按钮

    作者:Surpassme 来源:http://www.jianshu.com/p/08ee1929875f 声明:本文为原创文章,如需转载请在文章页面明显位置给出原文链接,谢谢. 单选按钮通常用在需要 ...

  8. Android Paint以及ColorFilter等

    我们可以通过Paint中大量的setter方法来为画笔设置属性: 这些属性大多我们都可以见名知意,很好理解,即便如此,哥还是带大家过一遍逐个剖析其用法,其中会不定穿插各种绘图类比如Canvas.Xfe ...

  9. Java 实现 WC.exe

    Github:https://github.com/YJOED/Code/tree/master/WC/src 一.题目:实现一个统计程序,它能正确统计程序文件中的字符数.单词数.行数,以及还具备其他 ...

  10. Netty 断线重连解决方案

    http://www.spring4all.com/article/889 本篇文章是Netty专题的第七篇,前面六篇文章如下: 高性能NIO框架Netty入门篇 高性能NIO框架Netty-对象传输 ...