大家好,我是小米,一個在代碼裏泡了九年的程序員。前幾天去面試一家互聯網公司,面試官笑眯眯地問我:“你瞭解 Tomcat 的 Container 架構嗎?”

我心想,這問題挺常見的,屬於那種“問不深就考概念、問深了就勸退”的經典類型。於是我開始講——沒想到,這一講,就聊了快半個小時。

今天就把我當時的回答完整覆盤給你聽,保證聽完後,你不再怕面試官問這個問題。

故事開頭:Tomcat 是一座“服務城市”

我特別喜歡把 Tomcat 比作一座城市。

在這座“城市”裏,有各種基礎設施:

  • Connector(連接器):它就像城市的“交通入口”,負責接待外來的請求(HTTP 或 AJP)。
  • Container(容器):它是城市的“核心區域”,負責處理這些請求、執行 Servlet、返回結果。

可以這麼説,Connector 接收請求,Container 處理請求。

而 Container 的內部,其實是一個層層嵌套、各司其職的“小宇宙”。

如果把它比作一座行政體系,那它大概長這樣:

Engine(發動機) → Host(主機) → Context(上下文) → Wrapper(包裝器)

聽起來有點抽象?別急,我們慢慢拆。

Engine:一切請求的總管

Engine 是整個 Container 體系的頂層容器,就像一座城市的“市政府”。

當 Connector 把請求交給 Engine 時,Engine 要決定:

  • 這個請求該交給哪台主機(Host)?
  • 用哪個 Web 應用(Context)去處理?
  • 最後哪個具體的 Servlet(Wrapper)來執行

Tomcat 默認只有一個 Engine,名字叫 Catalina(這名字是不是很熟?Tomcat 的主類就叫這個)。

Engine 內部會註冊多個 Host,比如:

  • localhost
  • myapp.company.com
  • test.company.com

Engine 根據請求頭裏的 Host 值去匹配對應的 Host。

換句話説,Engine 是整個容器鏈的入口,負責路由請求到正確的主機。

Host:承載多個 Web 應用的主機

每個 Host 代表一台虛擬主機,也就是一個域名或主機名。

比如我們訪問:

http://localhost:8080/demo

這裏的 localhost 對應的就是一個 Host。

Host 的職責是:

  • 管理多個 Web 應用(Context)
  • 為每個應用分配獨立的 ClassLoader(類加載空間)
  • 隔離不同應用間的資源

每個 Host 下可以部署多個 Context,例如:

/demo /shop /blog

Host 的核心思想是“多租户”——不同項目可以共存而互不干擾。

Context:Web 應用的靈魂

如果説 Host 是一台服務器,那 Context 就是一款部署在服務器上的 Web 應用。

Context 是最重要的容器之一,它直接對應一個 Web 項目(比如 webapps/demo 目錄)。

Context 的職責包括:

  1. 管理 Servlet、Filter、Listener 等組件;
  2. 負責加載 web.xml、初始化應用;
  3. 負責分發請求到具體的 Servlet。

舉個例子,當我們訪問 /demo/hello 時:

  • Engine 根據主機名找到 Host;
  • Host 根據 /demo 找到對應的 Context;
  • Context 再去定位具體的 Servlet(Wrapper)。

可以看到,Context 是實際業務處理的舞台,所有業務邏輯、配置、過濾器、攔截器都在這一級展開。

Wrapper:Servlet 的“外衣”

Wrapper 是 Container 體系中最底層、最貼近業務的一層。

它包裹着具體的 Servlet,比如 HelloServlet 或 UserLoginServlet。

Wrapper 負責:

  • 管理 Servlet 的生命週期(加載、初始化、銷燬);
  • 處理線程安全;
  • 調用真正的 service() 方法。

當請求一路從 Engine → Host → Context → Wrapper 傳遞下來時,最終在 Wrapper 層執行具體的 Servlet。

所以,Wrapper 是執行請求的最後一站。

四層容器的層級關係總結

我們用一個簡單的結構來表示它:

面試官笑了:終於有人能把 Tomcat 的 Container 講明白了!_Web

這四層是典型的“組合模式”(Composite Pattern),每一層都是 Container 的子類,都實現了 org.apache.catalina.Container 接口。

Tomcat 用這個設計實現了一個可擴展、可遞歸的容器層級體系——上層管理下層,下層專注具體邏輯。

Container 的核心接口設計

Tomcat 的 Container 架構其實高度面向接口設計,主要接口包括:

  • Container:所有容器的頂層接口;
  • Engine、Host、Context、Wrapper:四個具體子接口;
  • Pipeline / Valve:責任鏈機制,用於在請求處理前後執行攔截邏輯;
  • Lifecycle:生命週期管理接口。

當我們理解這些接口後,就能明白 Tomcat 的設計精髓:

它把請求的處理過程抽象成一個管道(Pipeline),讓每個 Valve 都能插入處理邏輯。

這就像在高速公路上設置多個收費站、檢查站,每個環節都能“攔一攔、看一看、做點事”。

Pipeline 與 Valve:Tomcat 的責任鏈魔法

在每個容器中,都有一個 Pipeline(管道),裏面裝着一連串的 Valve(閥門)。

請求進入時,會依次流過這些 Valve,每個 Valve 可以做:

  • 日誌記錄
  • 權限驗證
  • 過濾器處理
  • 性能統計
  • 最終調用下一級容器

比如在 Context 層的 Pipeline 中,常見的一個 Valve 是 StandardContextValve,它的作用是:

  • 找到請求對應的 Wrapper;
  • 調用 Wrapper 裏的 Servlet。

而在 Engine 層、Host 層,也都有各自的 Valve,比如:

  • ErrorReportValve:統一異常處理;
  • AccessLogValve:記錄訪問日誌。

這個機制讓 Tomcat 非常靈活,你可以輕鬆在任意層插入自定義邏輯。

請求在 Container 中的流轉之旅

讓我們以一次完整的請求為例,看看它的旅程:

1、Connector 接收請求

  • 監聽 8080 端口;
  • 解析 HTTP 協議;
  • 生成 Request 和 Response 對象;
  • 把它交給 Engine。

2、Engine 匹配 Host

  • 根據請求頭裏的 Host 字段找到對應的虛擬主機。

3、Host 匹配 Context

  • 根據 URI 前綴(如 /demo)找到對應的應用。

4、Context 匹配 Wrapper

  • 根據 Servlet 映射規則找到目標 Servlet。

5、Wrapper 調用 Servlet

  • 通過 Pipeline 調用 Servlet 的 service() 方法;
  • 最終執行我們的業務邏輯;
  • 返回響應。

整個流程,就像一場“層層轉發的旅程”:

Connector → Engine → Host → Context → Wrapper → Servlet

面試官笑了:終於有人能把 Tomcat 的 Container 講明白了!_主機名_02

面試官可能追問的進階問題

別以為講完層級關係就結束了,面試官很可能接着問:

“那 Container 和 Connector 之間怎麼通信?”

答:通過 Mapper 映射組件。

Mapper 根據請求 URL、主機名、路徑來定位目標容器(Host → Context → Wrapper)。

Connector 解析完請求後,會調用 Engine.getPipeline().getFirst().invoke(request, response),啓動整個責任鏈。

“每層容器如何實現解耦?”

答:Tomcat 使用接口 + 事件驅動機制,每個容器都實現 Lifecycle 接口,可以獨立啓動、銷燬、重新加載。這讓熱部署、應用隔離變得可行。

寫在最後:Tomcat 的“優雅之處”

當年第一次看 Tomcat 源碼,我差點被繞暈。

但當我真正理解 Container 的設計後,才發現它的優雅之處在於:

  • 用組合模式實現層級容器;
  • 用責任鏈實現靈活攔截;
  • 用生命週期接口實現可插拔模塊;
  • 用映射機制實現精準路由。

這不是“寫一堆類”的架構,而是一個能應對上億次請求的分層系統。

所以,當面試官問你“Tomcat 的 Container 架構”時,千萬別隻背誦那四層。要講出它們為什麼這樣設計、怎麼協作、能帶來什麼好處。

彩蛋:一句話總結送給你

Connector 負責“接”,Container 負責“處”。

Container 體系分四層:Engine、Host、Context、Wrapper。

每層用 Pipeline + Valve 實現責任鏈,

這就是 Tomcat 的“容器心臟”。

END

下次再有人問你這個問題,就別怕了。

你可以微微一笑,説:“Tomcat 的 Container,我太熟了——它其實是一場層層嵌套的優雅設計。”

如果你覺得這篇文章有點幫助,點個“在看”吧,我會繼續更新 Java 面試題系列,用故事幫你吃透底層源碼!

我是小米,一個喜歡分享技術的31歲程序員。如果你喜歡我的文章,歡迎關注我的微信公眾號“軟件求生”,獲取更多技術乾貨!