Spring MVC上下文容器在Web容器中是如何啟動的(源碼深入剖析)?
在Java Web開發中,理解Spring MVC如何與Tomcat等Web容器協同工作是掌握企業級應用開發的關鍵。本文將深入解析Spring MVC容器在Web容器中的啟動過程,揭示父子容器協作的奧秘。
在 Spring MVC 中,MVC 容器(即 DispatcherServlet 的 Web 應用上下文)的初始化過程是一個精密的協作機制。以下是詳細的啟動流程和關鍵代碼調用:
一、雙容器架構: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容器中的啟動過程
umizhang,公眾號:一只藍色猿Spring IOC容器在Web環境中是如何啟動的(源碼級剖析)?
3. 初始化 MVC 容器(DispatcherServlet 的WebApplicationContext)
Tomcat 等 Web 容器(Servlet 容器)啟動時調用 Servlet 的 init() 方法是一個由 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 容器啟動時,默認情況下 不會立即初始化 Servlet。Servlet 的初始化通常是延遲的(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. 設計意義與價值
- 生命周期管理:a. 容器完全控制 Servlet 的創建 → 初始化 → 服務 → 銷毀b. 保證資源有序初始化和釋放
- 依賴解耦a. Servlet 無需知道容器實現細節b. 通過標準接口 ServletConfig 獲取配置
- 資源預加載a. load-on-startup 避免首次請求延遲b. 特別適合 Spring MVC 這類重量級前端控制器
- 擴展性a. Spring 通過重寫 init() 插入自定義初始化邏輯b. 實現父子容器、組件初始化等高級特性
三、調試技巧
關鍵斷點位置:
- 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 標準規范。
擴展DispatcherServlet Diagram

Tomcat 中的完整調用棧

Servlet 3.0+ 無配置啟動(Java Config)
通過實現 WebApplicationInitializer 接口替代 web.xml:































