Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >SpringMVC执行流程和源码分析

SpringMVC执行流程和源码分析

原创
作者头像
在下是首席架构师
发布于 2022-08-01 13:17:15
发布于 2022-08-01 13:17:15
29200
代码可运行
举报
文章被收录于专栏:从入门到出门从入门到出门
运行总次数:0
代码可运行

SpringMVC执行流程:

  1. 用户点击某个请求路径,发起一个 HTTP request 请求,该请求会被提交到 DispatcherServlet(前端控制器);
  2. 由 DispatcherServlet 请求一个或多个 HandlerMapping(处理器映射器),并返回一个执行链(HandlerExecutionChain)。
  3. DispatcherServlet 将执行链返回的 Handler 信息发送给 HandlerAdapter(处理器适配器);
  4. HandlerAdapter 根据 Handler 信息找到并执行相应的 Handler(常称为 Controller);
  5. Handler 执行完毕后会返回给 HandlerAdapter 一个 ModelAndView 对象(Spring MVC的底层对象,包括 Model 数据模型和 View 视图信息);
  6. HandlerAdapter 接收到 ModelAndView 对象后,将其返回给 DispatcherServlet ;
  7. DispatcherServlet 接收到 ModelAndView 对象后,会请求 ViewResolver(视图解析器)对视图进行解析;
  8. ViewResolver 根据 View 信息匹配到相应的视图结果,并返回给 DispatcherServlet;
  9. DispatcherServlet 接收到具体的 View 视图后,进行视图渲染,将 Model 中的模型数据填充到 View 视图中的 request 域,生成最终的 View(视图);
  10. 视图负责将结果显示到浏览器(客户端)。
代码追踪

请求到达前端控制器的第一站,先做些准备工作

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
 * for the actual dispatching.
 */
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
   if (logger.isDebugEnabled()) {
      String requestUri = urlPathHelper.getRequestUri(request);
      logger.debug("DispatcherServlet with name '" + getServletName() + "' processing " + request.getMethod() +
            " request for [" + requestUri + "]");
   }

    //保护现场
   // Keep a snapshot of the request attributes in case of an include,
   // to be able to restore the original attributes after the include.
   Map<String, Object> attributesSnapshot = null;
   if (WebUtils.isIncludeRequest(request)) {
      logger.debug("Taking snapshot of request attributes before include");
      attributesSnapshot = new HashMap<String, Object>();
      Enumeration<?> attrNames = request.getAttributeNames();
      while (attrNames.hasMoreElements()) {
         String attrName = (String) attrNames.nextElement();
         if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
            attributesSnapshot.put(attrName, request.getAttribute(attrName));
         }
      }
   }

    //将框架相关信息存储至request,方便后面的处理器和视图用到
   // Make framework objects available to handlers and view objects.
   request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
   request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
   request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
   request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

   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 {
      //步骤1
      doDispatch(request, response);
   }
   finally {
      // Restore the original attribute snapshot, in case of an include.
      if (attributesSnapshot != null) {
         restoreAttributesAfterInclude(request, attributesSnapshot);
      }
   }
}

开始处理请求

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 mv = null;
                Object dispatchException = null;

                try {
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
		    //步骤2-3
                    mappedHandler = this.getHandler(processedRequest);
                    if (mappedHandler == null) {
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }
		    //步骤4
                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                    String method = request.getMethod();
                    boolean isGet = HttpMethod.GET.matches(method);
                    if (isGet || HttpMethod.HEAD.matches(method)) {
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }

                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
		    //步骤5-9
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }

                    this.applyDefaultViewName(processedRequest, mv);
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var20) {
                    dispatchException = var20;
                } catch (Throwable var21) {
                    dispatchException = new NestedServletException("Handler dispatch failed", var21);
                }
		//步骤10
                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
            } catch (Exception var22) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
            } catch (Throwable var23) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
            }

        } finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            } else if (multipartRequestParsed) {
                this.cleanupMultipart(processedRequest);
            }

        }
    }
    

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
搞懂Go泛型,看这一篇就够了
在Go语言1.17版本及后续的升级迭代中,泛型新特性无疑是非常重大的一次更新,这个特性的引入无疑为开发者们带来了更多的灵活性和代码复用性。虽然大部分功能不使用泛型也能正常实现,但是泛型带来的灵活性和效率值得我们进行学习和掌握,这篇文章就和大家一下讨论下Go语言的泛型。
闫同学
2025/01/22
5170
搞懂Go泛型,看这一篇就够了
Go 1.24 相比 Go 1.23 有哪些值得注意的改动?
Go 1.24 现在完全支持泛型类型别名(generic type aliases)。这意味着类型别名可以像定义的类型(defined types)一样,拥有自己的类型参数列表。在此之前,类型别名无法直接参数化。
Piper破壳
2025/05/06
3510
理解Golang的泛型
为降低interface{}带来的糟糕阅读体验,新增了any关键字,它实际上是一种语法糖,定义如下:
chandlerpan
2022/07/12
1.5K0
golang泛型基本用法
作者:matrix 被围观: 14 次 发布时间:2025-05-31 分类:Golang | 无评论 »
HHTjim 部落格
2025/06/01
1090
深入浅出Go泛型之泛型使用三步曲
大家好,我是渔夫子,又跟大家见面了。今天跟大家聊聊Go1.18中新增的泛型功能。。
Go学堂
2023/01/31
7840
终于!12年后Golang支持泛型了!(内含10个实例)
导语 | 泛型是一些语言的标配,可以极大地便利开发者,但Golang在之前并不支持泛型。在今年的Go1.17中已经发布了泛型的体验版,这一功能也是为1.18版本泛型正式实装做铺垫。本文将介绍一下泛型在Golang的使用样例及其泛型的发展历史,需要体验的同学可以使用:https://go2goplay.golang.org/或者自行在docker中安装版本。 一、泛型 (一)什么是泛型 谈泛型的概念,可以从多态看起,多态是同一形式表现出不同行为的一种特性,在编程语言中被分为两类,临时性多态和参数化多态。
腾讯云开发者
2021/11/09
2.9K0
Go 1.18泛型的局限性初探
Go 1.18 版本之后正式引入泛型,它被称作类型参数(type parameters),本文初步介绍 Go 中泛型的使用。长期以来 go 都没有泛型的概念,只有接口 interface 偶尔类似的充当泛型的作用,然而接口终究无法满足一些基本的泛型需求,比如这篇文章里,我们会尝试用 Go 的泛型循序渐进地实现一些常见的函数式特性,从而探索 Go 泛型的优势和不足。
yoyofx
2022/05/11
7310
Go 1.18 新增三大功能之一“泛型”怎么使用?
在 Go v1.18 中,Go 语言新增三个功能,分别是“泛型”、“模糊测试” 和 “工作区”。
frank.
2022/12/27
7700
Go 1.21 新内置函数:min、max 和 clear | 技术创作特训营第一期
Go 1.21.0 版本已经正式发布,它带来了许多新特性和改进。其中引入了的三个新内置函数:max、min 和 clear,接下来的内容将详细介绍这些函数的用途和特点。
陈明勇
2023/08/13
1.9K0
Go 1.21 新内置函数:min、max 和 clear | 技术创作特训营第一期
Go 中的泛型:激动人心的突破
在我们选择的编程语言中,我们多长时间会经历一次根本性的变化?有些语言会变化得更频繁一些,但还有些语言会比温布尔登更保守。
深度学习与Python
2022/04/19
5120
Go 泛型
泛型是程序设计语言的一种风格或范式。泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型。
孤烟
2023/01/06
5550
Go 泛型发展史与基本介绍
根据 Go 官方用户调查结果,在“你最想要的 Go 语言特性”这项调查中,泛型霸榜多年。你可以看下这张摘自2020 年 Go 官方用户调查结果的图片:
贾维斯Echo
2023/12/24
2810
Go 泛型发展史与基本介绍
三分钟学 Go 语言——函数深度解析(下) 可变参数
小熊这两天因为个人种种令人难受的原因,没有能更新,也没有提前请假,给大家道歉歉了。
机智的程序员小熊
2020/05/12
6950
深入理解Golang的泛型
2022年3月15日,争议非常大但同时也备受期待的泛型终于伴随着Go1.18发布了。
KunkkaWu
2023/07/12
1.5K0
深入理解Golang的泛型
Go 泛型
但这个函数只能接收[]int类型的参数,如果我们想支持[]float64类型的参数,我们就需要再定义一个reverseFloat64Slice函数。
f1sh
2024/07/31
970
Java & Go泛型对比
在当今软件开发领域中,泛型是一种强大的编程特性,它能够在不牺牲类型安全的前提下,实现代码的复用和灵活性。Java作为一种老牌的面向对象编程语言,在其长期的发展过程中,已经积累了丰富的泛型经验和应用场景。而Go语言作为一种相对较新的编程语言,也在不断探索和发展其泛型特性,以满足现代软件开发的需求。本文将对Java和Go语言的泛型进行比较和介绍,探讨它们的实现方式、语法特点以及适用场景,帮助读者更好地理解和应用泛型编程。
FunTester
2024/03/22
2080
Java & Go泛型对比
因势而变,因时而动,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang泛型(generic)的使用EP15
    事实上,泛型才是Go lang1.18最具特色的所在,但为什么我们一定要拖到后面才去探讨泛型?类比的话,我们可以想象一下给小学一年级的学生讲王勃的千古名篇《滕王阁序》,小学生有多大的概率可以理解作者的青云之志以及壮志难酬的愤懑心情?恐怕很难罢,是的,如果对Go lang的强类型语法没有一段时间的体验期,就很难理解泛型这种“反”静态语言概念。
用户9127725
2022/09/23
3120
因势而变,因时而动,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang泛型(generic)的使用EP15
搞懂Go泛型,看这一篇就够了
在Go语言1.17版本及后续的升级迭代中,泛型新特性无疑是非常重大的一次更新,这个特性的引入无疑为开发者们带来了更多的灵活性和代码复用性。虽然大部分功能不使用泛型也能正常实现,但是泛型带来的灵活性和效率值得我们进行学习和掌握,这篇文章就和大家一下讨论下Go语言的泛型。
闫同学
2025/01/20
3420
Golang 基础之基础语法梳理 (三)
接口 (interface) 定义了一个对象的行为规范, 只定义规范不实现,由具体的对象来实现规范的细节。
帽儿山的枪手
2022/03/20
5720
Golang 基础之基础语法梳理 (三)
Go 语言泛型使用详解
Go v1.18 开始支持泛型,距离 Go 当前版本 v1.23 已经迭代了 5 个大版本了。读者朋友们在使用 Go 语言开发时,是否已经习惯使用泛型了呢?
frank.
2024/11/19
2550
Go 语言泛型使用详解
相关推荐
搞懂Go泛型,看这一篇就够了
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验