day15-SpringMVC執行流程

来源:https://www.cnblogs.com/liyuelian/archive/2023/02/20/17139256.html
-Advertisement-
Play Games

SpringMVC執行流程 1.SpringMVC執行流程分析圖 例子 (1)創建 HaloHandler package com.li.web.debug; import org.springframework.stereotype.Controller; import org.springfra ...


SpringMVC執行流程

1.SpringMVC執行流程分析圖

例子

(1)創建 HaloHandler

package com.li.web.debug;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author 李
 * @version 1.0
 */
@Controller
public class HaloHandler {
    //編寫方法,響應請求,返回一個 ModelAndView對象
    @RequestMapping(value = "/debug/springmvc")
    public ModelAndView halo(HttpServletRequest request, HttpServletResponse response) {
        ModelAndView modelAndView = new ModelAndView();
        //對應到 WEB-INF/pages/ok.jsp (ok的前尾碼是你在視圖解析器中配置的前尾碼)
        modelAndView.setViewName("ok");
        //在model中放入數據 k-v,ModelAndView的屬性也會被springmvc放入到request域中
        modelAndView.addObject("name", "齊天大聖");
        return modelAndView;
    }
}

(2)創建ok.jsp,作為響應後跳轉的頁面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>ok</title>
</head>
<body>
<h1>進入到ok頁面</h1>
<h2>name-${requestScope.name}</h2>
</body>
</html>

2.源碼debug

我們以上述代碼為例子進行源碼分析。

(1)在 DispatcherServlet 的 doService 方法中打上斷點,在瀏覽器中訪問目標方法,可以看到游標跳轉到斷點處:當請求發送到伺服器時,tomcat 將 http 請求包裝成 request 對象,前端控制器 DispatcherServlet 使用 doService() 方法接收這個 request 對象。

image-20230220213910330 image-20230220203713801

(2)點擊 step over 前進,可以看到這裡的 getWebApplicationContext() 就是 spring 容器對象。也就是說,當接收到url請求的時候,前端控制器就會進行spring 容器的初始化,將各種 bean 放入到容器中。

image-20230220204141473

(3)點擊 step over,在經過一系列處理之後調用了 doDispatch() 方法。這是一個核心的方法。

image-20230220204445920

(4)點擊 step into,進入 doDispatch() 方法,該方法中首先定義了一個處理器執行鏈,它用於存放攔截器(多個)和目標 Handler。然後定義了ModelAndView 對象,用於存放視圖信息和數據。

image-20230220213959367 image-20230220205326737

執行下麵的語句後,就通過映射拿到了處理器執行鏈 HandlerExecutionChain 的目標 Handler 和攔截器鏈

image-20230220210019024

(5)點擊 step over,跳到如下:獲取適配器,包含要執行的目標 Handler

image-20230220210743139 image-20230220214118074

(6)點擊 step over,跳到如下:調用 handle() 方法,進行反射調用目標 Handler。

image-20230220211201477

(7)點擊 step into,進入到 handle 方法中調用的 handleInternal() 方法,handleInternal() 方法中反射調用了目標 Handler的方法,然後返回視圖對象。

image-20230220211812556 image-20230220214704657

(8)在目標方法中打上斷點,點擊 resume 進入目標方法

image-20230220212955654

(9)點擊 step over,ModelAndView 對象返回給適配器。

image-20230220213514030 image-20230220214807691

(10)然後返回到第7步的方法中,因此第7步中返回的視圖就是目標方法操作後返回的視圖對象

image-20230220215320257

(11)繼續一直點擊 step over,方法 return 返回到第6步,將獲取的視圖對象返回給前端控制器。

image-20230220215703488 image-20230220215805035

(12)點擊 step over,在前端控制器的 doService 方法中執行如下語句,processDispatchResult() 方法對前面返回的視圖進行解析。

image-20230220220003548

(13)step into 進入processDispatchResult 方法,該方法調用 render() 進行渲染。

image-20230220220233835

(14)render() 方法從 ModelAndView 對象中得到視圖名稱 viewName,如果 viewName 不為空,就進行視圖解析。

image-20230220220630961

resolveViewName() 方法進行視圖解析,然後返回 view 給前端控制器。

@Nullable
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
      Locale locale, HttpServletRequest request) throws Exception {

   if (this.viewResolvers != null) {
      for (ViewResolver viewResolver : this.viewResolvers) {
         View view = viewResolver.resolveViewName(viewName, locale);
         if (view != null) {
            return view;
         }
      }
   }
   return null;
}
image-20230220220937160

(15)返回前端控制器之後,又調用 View的 render() 方法進行視圖的渲染。

註意和前端控制器的 render 方法區分

image-20230220221538252 image-20230220222131962

View 的 render() 方法:

@Override
public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
      HttpServletResponse response) throws Exception {

   if (logger.isDebugEnabled()) {
      logger.debug("View " + formatViewName() +
            ", model " + (model != null ? model : Collections.emptyMap()) +
            (this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes));
   }

   Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
   prepareResponse(request, response);
    //渲染合併輸出模型
   renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}

renderMergedOutputModel() 方法通過請求轉發跳轉到相應頁面:

image-20230220221857739 image-20230220222033914

(16)最後 tomcat 返回 http響應,瀏覽器顯示頁面

image-20230220222507677

3.練習

  1. 將之前的 SpringMVC 異常處理相關代碼和案例寫一遍
  2. 簡述原生的 SpringMVC 執行流程,並畫出示意圖
  3. debug SpringMVC 的執行流程源碼,加深理解

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 HTML頁面載入過程會發生什麼?因為瀏覽器網路拉取資源是多線程的,但是dom樹的操作都是在一個線程中的,所以網頁資源的解析、js載入、dom樹渲染都是一個線程執行,所以就會線程任務就會相互搶占,先來先執行。而當瀏覽器載入html文件時,會 ...
  • JavaScript數組方法大全 趁著有時間,總結了下數組所有的屬性和方法,記錄博客,便於後續使用 at() at方法,用於獲取數組中,對應索引位置的值,不能修改。 語法:array.at(count); 參數:count,數組的索引值 返回值:返回該索引在數組中對應的值,如果count大於等於數組 ...
  • RegExp() 在es5中,RegExp的構造函數參數有兩種情況 1、字元串 2、正則表達式 // 第一種情況 let regex = new RegExp('abc', 'i') // 第二種情況 let regex2 = /abc/i 這兩種情況是等價的 let s = 'abc' regex ...
  • 在 HTML 中引入 JavaScript 文件時,可以使用 defer 屬性,該屬性可以推遲(defer)腳本的執行,即等到整個 HTML 文檔解析完畢後才執行腳本。 使用 defer 屬性可以避免在解析 HTML 文檔的過程中阻塞頁面的渲染,提高頁面載入的速度。 同時,defer 屬性還可以確保 ...
  • 在官方示例的沙盒裡寫東西是真方便 Cesium中有兩種對象可以添加到場景中,Entity、Primitive。Entity對用戶更友好,方便使用,但是靈活性和性能差一些。Primitive,支持自定義幾何形狀和幾何對象的材質,可以實現更複雜的效果。 1.polygon(面) var square = ...
  • 一、背景 遠程服務將電腦程式的工作範圍從單機擴展到網路,從本地延伸至遠程,是構建分散式系統的首要基礎。遠程服務調用(Remote Procedure Call,RPC)在電腦科學中已經存在了超過四十年時間。但很多人無法明確區分RPC與Rest。本文就講一講RPC和Rest的本質區別。 二、分析 ...
  • 談到java中的併發,我們就避不開線程之間的同步和協作問題,談到線程同步和協作我們就不能不談談jdk中提供的AbstractQueuedSynchronizer(翻譯過來就是抽象的隊列同步器)機制; (一)、AQS中的state和Node含義: AQS中提供了一個int volatile state ...
  • 導入依賴 <!--代碼生成器--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.4.1</version> </dependency> ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...