Spring MVC上下文容器在Web容器中是如何啟動的(源碼深入剖析)?

文章目錄

    • 一、雙容器架構:MVC容器與根容器的關系
    • 二、啟動全流程解析
      • 1. 啟動流程全景圖
      • 2. 初始化根容器(Root WebApplicationContext)
        • 2.1 Tomcat 中啟動入口源碼解析
        • 2.2 Spring 根上下文啟動源碼解析
      • 3. 初始化 MVC 容器(DispatcherServlet 的 WebApplicationContext)
        • 3.1 Tomcat 中啟動入口源碼解析
        • 3.2 Spring MVC上下文啟動源碼解析
          • 1. ★MVC容器初始化入口:HttpServletBean
          • 2. 創建 MVC 容器:FrameworkServlet
          • 3. 核心邏輯:initWebApplicationContext()
          • 4. 創建MVC子容器:createWebApplicationContext()
          • 5. 配置并刷新容器:configureAndRefreshWebApplicationContext()
          • 6. 初始化 MVC 組件:DispatcherServlet 的 onRefresh()
        • 3.3 核心啟動流程
      • 4. 關鍵設計解析
        • 1. 父子容器設計的優勢
        • 2. 設計意義與價值
    • 三、調試技巧
    • 四、總結
    • 擴展
      • DispatcherServlet Diagram
      • Tomcat 中的完整調用棧
      • Servlet 3.0+ 無配置啟動(Java Config)

在Java Web開發中,理解Spring MVC如何與Tomcat等Web容器協同工作是掌握企業級應用開發的關鍵。本文將深入解析Spring MVC容器在Web容器中的啟動過程,揭示父子容器協作的奧秘。

在上一篇中詳細介紹了 Spring IOC容器在web容器中的啟動過程,這篇進一步了解下Spring MVC容器(即 Web 應用上下文)是如何在web容器(如 Tomcat、Jetty)中啟動并生效的。在 Spring MVC 中,MVC 容器(即 DispatcherServletWeb 應用上下文)的初始化過程是一個精密的協作機制。以下是詳細的啟動流程和關鍵代碼調用:

一、雙容器架構:MVC容器與根容器的關系

Spring MVC采用父子容器設計,實現業務層與Web層的關注點分離:
在這里插入圖片描述

  • 根容器:由ContextLoaderListener創建,管理業務層和數據層Bean
  • MVC容器:由DispatcherServlet創建,管理Web層組件
  • 依賴規則:子容器可訪問父容器的Bean,反之則不行

二、啟動全流程解析

1. 啟動流程全景圖

在這里插入圖片描述

Web 容器啟動

  • Web 容器(如 Tomcat)啟動時,會加載 web.xml(或 Servlet 3.0+ 的注解配置)。
  • 容器根據配置初始化 ServletContext(全局上下文),作為整個 Web 應用的共享空間。
  • ServletContext 基礎上展開Spring Web 容器的一系列啟動初始化

2. 初始化根容器(Root WebApplicationContext)

2.1 Tomcat 中啟動入口源碼解析

源碼入口StandardContext.startInternal()

在這里插入圖片描述
在這里插入圖片描述

核心點:上面 Tomcat 源碼中 listener.contextInitialized(event) 方法會執行到 Spring ContextLoaderListener.contextInitialized()方法, 從而初始化Spring Web 根上下文(IOC容器),建立起在Web環境中Spring IOC容器。

2.2 Spring 根上下文啟動源碼解析

源碼入口ContextLoaderListener.contextInitialized()

[提示]:詳細解析過程可查閱: Spring IOC容器在web容器中的啟動過程

3. 初始化 MVC 容器(DispatcherServlet 的 WebApplicationContext)

Tomcat 等 Web 容器(Servlet 容器)啟動時調用 Servletinit() 方法是一個由 Java Servlet 規范定義的標準過程,其細節如下:

3.1 Tomcat 中啟動入口源碼解析

源碼入口StandardContext.startInternal()

在這里插入圖片描述
Servlet 加載機制: StandardContext.loadOnStartup()
在這里插入圖片描述
核心代碼:StandardWrapper.loadServlet()
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

核心點:上面的 Tomcat 源碼中GenericServlet.init()方法實際會調用到 Spring DispatcherServlet.load()方法(DispatcherServlet的繼承鏈:DispatcherServlet → FrameworkServlet → HttpServletBean→ HttpServlet→ GenericServlet),從而初始化Spring MVC 子上下文(Web IOC容器),建立起在Web環境中Spring MVC架構來接收處理 HTTP 請求。

疑問點:為什么調用 servlet.init()?

  • Servlet 規范要求,所有 Servlet 必須實現 javax.servlet.Servlet 接口;Java Servlet 規范(JSR 369)明確定義:
  • “After the servlet object is instantiated, the container must initialize the servlet before it can handle requests. The container initializes the servlet by calling the init(ServletConfig) method.”

  • load-on-startup 控制:在 web.xml 中配置的 <load-on-startup> 決定初始化時機;
    • 延遲加載(默認行為):在 Tomcat 容器啟動時,默認情況下 不會立即初始化 ServletServlet 的初始化通常是延遲的(lazy loading),即在第一次接收到與該 Servlet 相關的請求時才會進行初始化。這種行為是由 Servlet 規范定義的,目的是為了節省資源。
    • 啟動時加載(eager loading):如果在 web.xml 中為 Servlet 配置了 <load-on-startup> 元素,Tomcat 會在容器啟動時初始化該 Servlet。其值為一個整數,表示加載順序。0或正值,值越小,優先級越高。負值或未指定,首次請求時初始化。
3.2 Spring MVC上下文啟動源碼解析

源碼入口DispatcherServlet.init()

  • 配置web.xml:在這里插入圖片描述

由于繼承關系,實際初始化入口類為DispatcherServlet的父類HttpServletBean,源碼位置:org.springframework.web.servlet.HttpServletBean

1. ★MVC容器初始化入口:HttpServletBean

在這里插入圖片描述

2. 創建 MVC 容器:FrameworkServlet

在這里插入圖片描述

3. 核心邏輯:initWebApplicationContext()

在這里插入圖片描述

4. 創建MVC子容器:createWebApplicationContext()

在這里插入圖片描述
在這里插入圖片描述

5. 配置并刷新容器:configureAndRefreshWebApplicationContext()

在這里插入圖片描述

6. 初始化 MVC 組件:DispatcherServlet 的 onRefresh()

在這里插入圖片描述

3.3 核心啟動流程
  • DispatcherServlet 初始化時調用 init() 方法。
  • 創建 子應用上下文(專用于 Web 層的容器),自動將根上下文設置為父容器。
  • 加載 contextConfigLocation 指定的 MVC 配置(如 Controller、視圖解析器等)。
  • 刷新子上下文(refresh() 方法),初始化所有 MVC 相關的 組件Bean。

通過此流程,Spring MVC 實現了 Web 層組件的精確控制,同時通過父子容器隔離了業務層與 Web 層的 Bean 管理。

4. 關鍵設計解析

1. 父子容器設計的優勢
  • 關注點分離:業務層與Web層解耦
  • 資源隔離:避免Controller污染業務層
  • 靈活配置:不同容器可獨立配置
  • 依賴可控:子容器可訪問父容器,反之不行
  • 獨立刷新:Web層重啟不影響業務層
2. 設計意義與價值
  1. 生命周期管理
    • 容器完全控制 Servlet 的創建 → 初始化 → 服務 → 銷毀
    • 保證資源有序初始化和釋放
  2. 依賴解耦
    • Servlet 無需知道容器實現細節
    • 通過標準接口 ServletConfig 獲取配置
  3. 資源預加載
    • load-on-startup 避免首次請求延遲
    • 特別適合 Spring MVC 這類重量級前端控制器
  4. 擴展性
    • Spring 通過重寫 init() 插入自定義初始化邏輯
    • 實現父子容器、組件初始化等高級特性

三、調試技巧

關鍵斷點位置:

  • FrameworkServlet.initWebApplicationContext()
  • AbstractApplicationContext.refresh()
  • DispatcherServlet.initStrategies()
  • RequestMappingHandlerMapping.afterPropertiesSet()

四、總結

Spring MVC在Web容器中的啟動是一個精密的協作過程:整個啟動過程Servlet 規范 驅動(監聽器、Servlet 生命周期),Spring 在此基礎上擴展上下文層次。

  • Tomcat 通過load-on-startup機制觸發Servlet初始化
  • ContextLoaderListener 創建根容器管理業務Bean
  • DispatcherServlet 創建子容器管理Web組件。
  • 父子容器 通過setParent()建立層級關系。
  • 父子容器refresh() 方法觸發完整的Bean初始化流程

通過這種分層設計,Spring 實現了關注點分離(業務層 vs Web 層),同時確保依賴注入的正確性。 通過這套機制,Tomcat
等容器保證了 Spring MVC 這類框架能在正確的時間點初始化自己的核心組件,同時遵循 Java EE 標準規范。


End!

擴展

DispatcherServlet Diagram

在這里插入圖片描述

Tomcat 中的完整調用棧

// Tomcat 啟動入口
Bootstrap.main()Catalina.load()StandardServer.start()StandardService.start()StandardEngine.start()StandardHost.start()StandardContext.start()StandardContext.startInternal()StandardContext.fireLifecycleEvent()  // 觸發監聽器(初始化Spring Web根容器)StandardContext.loadOnStartup()       // 關鍵:啟動時加載ServletStandardWrapper.loadServlet()DispatcherServlet.init(ServletConfig)  // Spring MVC子容器入口HttpServletBean.init()FrameworkServlet.initServletBean()initWebApplicationContext()  // 初始化MVC容器

Servlet 3.0+ 無配置啟動(Java Config)

通過實現 WebApplicationInitializer 接口替代 web.xml

public class MyWebAppInitializer implements WebApplicationInitializer {@Overridepublic void onStartup(ServletContext servletContext) {// 1. 創建根容器AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();rootContext.register(RootConfig.class);servletContext.addListener(new ContextLoaderListener(rootContext));// 2. 創建 MVC 容器(子容器)AnnotationConfigWebApplicationContext mvcContext = new AnnotationConfigWebApplicationContext();mvcContext.register(WebConfig.class);// 3. 注冊 DispatcherServletDispatcherServlet servlet = new DispatcherServlet(mvcContext);ServletRegistration.Dynamic registration = servletContext.addServlet("dispatcher", servlet);registration.addMapping("/");registration.setLoadOnStartup(1);}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/90235.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/90235.shtml
英文地址,請注明出處:http://en.pswp.cn/web/90235.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【iOS】編譯和鏈接、動靜態庫及dyld的簡單學習

文章目錄編譯和鏈接1??核心結論&#xff1a;一句話區分2??編譯過程&#xff1a;從源代碼到目標文件&#xff08;.o&#xff09;2.1 預處理&#xff08;Preprocessing&#xff09;&#xff1a;“替換變量復制粘貼”2.2 編譯&#xff08;Compilation&#xff09;&#xff1a;…

金山辦公WPS項目產品總監陳智新受邀為第十四屆中國PMO大會演講嘉賓

全國PMO專業人士年度盛會珠海金山辦公軟件有限公司WPS項目產品總監 陳智新先生 受邀為“PMO評論”主辦的2025第十四屆中國PMO大會演講嘉賓&#xff0c;演講議題為&#xff1a;中小團隊PMO的成長之路&#xff0c;敬請關注&#xff01;議題簡要&#xff1a;在競爭激烈、需求多變的…

web安全 | docker復雜環境下的內網打點

本文作者&#xff1a;Track-syst1m一.前言本文涉及的相關漏洞均已修復、本文中技術和方法僅用于教育目的&#xff1b;文中討論的所有案例和技術均旨在幫助讀者更好地理解相關安全問題&#xff0c;并采取適當的防護措施來保護自身系統免受攻擊。二.大概流程1. 外網打點? 漏洞利…

iTwin 幾何屬性獲取

面積體積半徑獲取幾何屬性&#xff0c;如面積&#xff0c;體積&#xff0c;半徑&#xff0c;可以使用getMassProperties這個接口async onGetMassProperty(){const vp IModelApp.viewManager.selectedView;const iModel vp?.iModel;if (!iModel) return;console.log("iM…

OpenLayers 快速入門(九)Extent 介紹

看過的知識不等于學會。唯有用心總結、系統記錄&#xff0c;并通過溫故知新反復實踐&#xff0c;才能真正掌握一二 作為一名摸爬滾打三年的前端開發&#xff0c;開源社區給了我飯碗&#xff0c;我也將所學的知識體系回饋給大家&#xff0c;助你少走彎路&#xff01; OpenLayers…

LeetCode 121. 買賣股票的最佳時機 LeetCode 122. 買賣股票的最佳時機II LeetCode 123.買賣股票的最佳時機III

LeetCode 121. 買賣股票的最佳時機嘗試一&#xff1a;暴力解決方法常用兩個指針去遍歷prices數組&#xff0c;dp[i]用于記錄在第i天所獲得的最大利潤。時間復雜度是O(N^2)&#xff0c;超出時間限制。Codeclass Solution(object):def maxProfit(self, prices):"""…

【LeNet網絡架構】——深度學習.卷積神經網絡

目錄 1 MLP 2 LeNet簡介 3 Minst數據集 3.1 MINST數據集簡介 3.2 MNIST數據集的預處理 4 LeNet手寫數字識別 LeNet由Yann Lecun 提出&#xff0c;是一種經典的卷積神經網絡&#xff0c;是現代卷積神經網絡的起源之一。Yann將該網絡用于郵局的郵政的郵政編碼識別&#xff…

Python筆記完整版

常用pip源 &#xff08;1&#xff09;阿里云 http://mirrors.aliyun.com/pypi/simple/&#xff08;2&#xff09;豆瓣 http://pypi.douban.com/simple/&#xff08;3&#xff09;清華大學 https://pypi.tuna.tsinghua.edu.cn/simple/&#xff08;4&#xff09;中國科學技術大學…

2025 鴻蒙創新賽又來了,萬少教你如何強勢切入 HarmonyOS AI特性

2025 鴻蒙創新賽又來了&#xff0c;萬少教你如何強勢切入 前言 ? 2025 華為HarmonyOS 創新賽又來了&#xff0c;創新賽是鴻蒙生態最大規模開發者官方賽事&#xff0c;最高獲百萬激勵。 參賽資格 面向所有開發者開放以隊伍的形式來參加&#xff0c;可以一個人報名一個隊伍&a…

【智能模型系列】Unity通過訪問Ollama調用DeepSeek模型進行本地部署

【智能模型系列】Unity通過訪問Ollama調用DeepSeek模型進行本地部署 目錄 一、前言 二、環境準備 三、核心代碼解析 1、參數配置 2. CallDeepSeek.cs - API交互控制器 3、 MainPanel.cs - 用戶界面控制器 四、源碼 一、前言 在本教程中,我將分享如何在Unity中集成本地…

什么是5G-A三防平板?有什么特點?哪些領域能用到?

在工業自動化與數字化轉型浪潮中&#xff0c;三防平板電腦已成為“危、急、特”場景的核心工具。這類設備不僅具備堅固耐用的物理防護特性&#xff0c;更融合了先進的通信技術與智能處理能力。而隨著5G技術向5G-A階段演進&#xff0c;新一代三防平板正為行業應用注入全新動能。…

Flink實時流量統計:基于窗口函數與Redis Sink的每小時PV監控系統(學習記錄)

題目&#xff1a;利用flink統計網站瀏覽量&#xff0c;并寫入redis。利用窗口函數以及算子實現每小時PV&#xff08;網站的頁面瀏覽量&#xff09;統計&#xff0c;對統計后結果數據格式進行設計&#xff0c;存儲至Redis中&#xff08;利用sink將處理后結果數據輸出到redis數據…

使用Imgui和SDL2做的一個彈球小游戲-Bounze

使用Imgui和SDL2做的一個彈球小游戲-Bounze 油管上面TheCherno博主分享的一個視頻FIRST GAME in C! Did He Do a Good Job? // Code Review (C/SDL2)里面分享了一個Github項目&#xff1a; https://github.com/staticaron/Bounze 使用了Imgui和SDL2&#xff0c;并且可以設置音…

SQL 中 CASE WHEN 及 SELECT CASE WHEN 的用法

SQL 中 CASE WHEN 及 SELECT CASE WHEN 的用法 CASE WHEN 是 SQL 中非常實用的條件表達式&#xff0c;它允許你在查詢中實現條件邏輯。以下是詳細的用法說明&#xff1a; 1. 基本語法結構 CASE WHEN condition1 THEN result1WHEN condition2 THEN result2...ELSE default_resul…

CentOS 7 Linux 基礎知識點匯總

&#x1f427; CentOS 7 Linux 基礎知識點匯總為方便初學者快速掌握 CentOS 7 系統的核心操作&#xff0c;本文檔整理了常用系統命令、快捷鍵、目錄結構及文件后綴名等基礎內容&#xff0c;適合入門參考。 一、常見系統命令 &#x1f50d; 命令行提示符說明 終端中的提示符包含…

突發限制下的破局之路:國產之光 Lynx 重構 AI 開發安全壁壘

繼 Pro 套餐 “明升暗降” 爭議后&#xff0c;Cursor 本周再掀波瀾 —— 包括 Claude 系列、GPT-4 在內的主流模型一夜之間對中國用戶全面封禁。開發者社群瞬間沸騰&#xff0c;“付費卻用不了”“項目數據導不出” 的焦慮刷屏&#xff0c;境外工具的政策波動再次給行業敲響警鐘…

滲透測試實戰 | docker復雜環境下的內網打點

本文作者&#xff1a;Track-syst1m一.前言本文涉及的相關漏洞均已修復、本文中技術和方法僅用于教育目的&#xff1b;文中討論的所有案例和技術均旨在幫助讀者更好地理解相關安全問題&#xff0c;并采取適當的防護措施來保護自身系統免受攻擊。二.大概流程1. 外網打點漏洞利用?…

阿里云服務器 CentOS 7 安裝 MySQL 8.4 超詳細指南

阿里云服務器 CentOS 7 安裝 MySQL 8.4 超詳細指南 一、準備工作 系統要求&#xff1a; CentOS 7.9 64位2 核&#xff08;vCPU&#xff09;2 GiBroot 用戶權限 服務器連接工具&#xff1a; FinalShell 下載安裝包&#xff1a; 訪問 MySQL 官網選擇版本&#xff1a;MySQL 8.4.0…

解決 Electron 中 window.open 打開新窗口的各種“坑”

嘿&#xff0c;各位開發者們&#xff01;今天我們要聊聊在使用 Electron 時遇到的一個經典問題&#xff1a;如何正確地使用 window.open 來打開新窗口&#xff1f; 這聽起來似乎很簡單&#xff0c;但實際上卻充滿了各種“驚喜”&#xff08;或者說“驚嚇”&#xff09;。別擔心…

朝歌智慧盤古信息:以IMS MOM V6重構國產化智能終端新生態

隨著5G、云計算、AI、大數據等技術深度滲透&#xff0c;智能終端行業正迎來場景化創新的爆發期。面對市場需求升級與技術迭代壓力&#xff0c;國產化智能終端領域領軍企業——廣東朝歌智慧互聯科技有限公司&#xff08;以下簡稱“朝歌智慧”&#xff09;&#xff0c;基于集團“…