前言
整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。
開源專案
從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。
系列文章
web server apache tomcat11-01-官方文件入門介紹
web server apache tomcat11-02-setup 啟動
web server apache tomcat11-03-deploy 如何部署
web server apache tomcat11-04-manager 如何管理?
web server apache tomcat11-06-Host Manager App -- Text Interface
web server apache tomcat11-07-Realm Configuration
web server apache tomcat11-08-JNDI Resources
web server apache tomcat11-09-JNDI Datasource
web server apache tomcat11-10-Class Loader
...
概述
像許多伺服器應用程式一樣,Tomcat 安裝了各種類載入器(即實現 java.lang.ClassLoader 的類),以允許容器的不同部分以及在容器上執行的 Web 應用程式訪問不同的類和資源庫。
此機制用於提供 Servlet 規範 2.4 版中定義的功能,特別是第 9.4 節和第 9.6 節。
在 Java 環境中,類載入器被安排成父子樹。通常,當類載入器被要求載入特定的類或資源時,它首先將請求委託給父類載入器,然後僅在父類載入器無法找到請求的類或資源時才檢視自己的儲存庫。
請注意,Web 應用程式類載入器的模型與此略有不同,如下所述,但主要原則相同。
當啟動 Tomcat 時,它建立了一組類載入器,這些類載入器按以下父子關係組織,其中父類載入器位於子類載入器之上:
Bootstrap
|
System
|
Common
/ \
Webapp1 Webapp2 ...
每個類載入器的特性,包括它們可見的類和資源的來源,將在以下部分詳細討論。
類載入器定義
如上圖所示,Tomcat 在初始化時建立以下類載入器:
-
Bootstrap — 此類載入器包含 Java 虛擬機器提供的基本執行時類,以及位於系統擴充套件目錄 ($JAVA_HOME/jre/lib/ext) 中的任何 JAR 檔案中的類。注意:一些 JVM 可能將其實現為一個以上的類載入器,或者它可能根本不可見(作為類載入器)。
-
System — 此類載入器通常是從 CLASSPATH 環境變數的內容初始化的。所有這些類對於 Tomcat 內部類和 Web 應用程式都是可見的。但是,標準的 Tomcat 啟動指令碼 ($CATALINA_HOME/bin/catalina.sh 或 %CATALINA_HOME%\bin\catalina.bat) 完全忽略 CLASSPATH 環境變數本身的內容,並且改為從以下儲存庫構建 System 類載入器:
- $CATALINA_HOME/bin/bootstrap.jar — 包含用於初始化 Tomcat 伺服器的 main() 方法,以及它依賴的類載入器實現類。
- $CATALINA_BASE/bin/tomcat-juli.jar 或 $CATALINA_HOME/bin/tomcat-juli.jar — 日誌記錄實現類。這些包括對 java.util.logging API 的增強類,稱為 Tomcat JULI,以及 Tomcat 內部使用的 Apache Commons Logging 庫的包重新命名副本。有關更多詳細資訊,請參閱日誌記錄文件。
- 如果 $CATALINA_BASE/bin 中存在 tomcat-juli.jar,則會使用它,而不是 $CATALINA_HOME/bin 中的 tomcat-juli.jar。在某些日誌記錄配置中,這很有用。
- $CATALINA_HOME/bin/commons-daemon.jar — 來自 Apache Commons Daemon 專案的類。此 JAR 檔案不包含在 catalina.bat|.sh 指令碼構建的 CLASSPATH 中,但是在 bootstrap.jar 的清單檔案中引用了它。
-
Common — 此類載入器包含了對 Tomcat 內部類和所有 Web 應用程式都可見的其他類。
通常情況下,應用程式類不應放在此處。此類載入器搜尋的位置由 $CATALINA_BASE/conf/catalina.properties 中的 common.loader 屬性定義。預設設定將按照它們列出的順序搜尋以下位置:
- $CATALINA_BASE/lib 中未打包的類和資源
- $CATALINA_BASE/lib 中的 JAR 檔案
- $CATALINA_HOME/lib 中未打包的類和資源
- $CATALINA_HOME/lib 中的 JAR 檔案
預設情況下,這包括以下內容:
- annotations-api.jar — Jakarta Annotations 2.1.1 類。
- catalina.jar — Tomcat 的 Catalina servlet 容器部分的實現。
- catalina-ant.jar — 可選。用於與 Manager web 應用程式一起使用的 Tomcat Catalina Ant 任務。
- catalina-ha.jar — 可
選。基於 Tribes 構建的提供會話叢集功能的高可用性包。
-
catalina-ssi.jar — 可選。伺服器端包含模組。
-
catalina-storeconfig.jar — 可選。從當前狀態生成 XML 配置檔案。
-
catalina-tribes.jar — 可選。高可用性包使用的組通訊包。
-
ecj-*.jar — 可選。用於將 JSP 編譯為 Servlet 的 Eclipse JDT Java 編譯器。
-
el-api.jar — 可選。EL 6.0 API。
-
jakartaee-migration-*-shaded.jar — 可選。提供將 Web 應用程式從 Java EE 8 轉換為 Jakarta EE 9 的功能。
-
jasper.jar — 可選。Tomcat Jasper JSP 編譯器和執行時。
-
jasper-el.jar — 可選。Tomcat EL 實現。
-
jaspic-api.jar — Jakarta Authentication 3.0 API。
-
jsp-api.jar — 可選。Jakarta Pages 4.0 API。
-
servlet-api.jar — Jakarta Servlet 6.1 API。
-
tomcat-api.jar — Tomcat 定義的幾個介面。
-
tomcat-coyote.jar — Tomcat 聯結器和實用程式類。
-
tomcat-dbcp.jar — 可選。基於 Apache Commons Pool 2 和 Apache Commons DBCP 2 的包重新命名副本的資料庫連線池實現。
-
tomcat-i18n-**.jar — 可選的 JAR,包含其他語言的資源包。由於預設包含了每個單獨 JAR 中的預設包,因此如果不需要對訊息進行國際化,則可以安全地刪除它們。
-
tomcat-jdbc.jar — 可選。另一種資料庫連線池實現,稱為 Tomcat JDBC 池。有關更多詳細資訊,請參閱文件。
-
tomcat-jni.jar — 提供與 Tomcat Native 庫的整合。
-
tomcat-util.jar — Apache Tomcat 各個元件使用的公共類。
-
tomcat-util-scan.jar — 提供 Tomcat 使用的類掃描功能。
-
tomcat-websocket.jar — 可選。Jakarta WebSocket 2.1 實現。
-
websocket-api.jar — 可選。Jakarta WebSocket 2.1 API。
-
websocket-client-api.jar — 可選。Jakarta WebSocket 2.1 客戶端 API。
-
WebappX — 為部署在單個 Tomcat 例項中的每個 Web 應用程式建立一個類載入器。您的 Web 應用程式的 /WEB-INF/classes 目錄中的所有未打包的類和資源,以及您的 Web 應用程式的 /WEB-INF/lib 目錄下的 JAR 檔案中的類和資源,都會對該 Web 應用程式可見,但對其他 Web 應用程式不可見。
如上所述,Web 應用程式類載入器與預設的 Java 委託模型有所不同(根據 Servlet 規範 2.4 第 9.7.2 節 Web 應用程式類載入器的建議)。當處理對 Web 應用程式的 WebappX 類載入器的載入類的請求時,此類載入器首先會查詢本地儲存庫,而不是委託給父級再查詢。但也有一些例外。JRE 基本類的一部分無法被覆蓋。有一些例外,比如可以使用可升級模組功能覆蓋的 XML 解析器元件。最後,對於由 Tomcat 實現的規範(Servlet、JSP、EL、WebSocket),Web 應用程式類載入器始終首先委託。Tomcat 中的所有其他類載入器都遵循通常的委派模式。
因此,從 Web 應用程式的角度來看,類或資源載入按以下順序查詢儲存庫:
- JVM 的 Bootstrap 類
- 您的 Web 應用程式的 /WEB-INF/classes
- 您的 Web 應用程式的 /WEB-INF/lib/*.jar
- System 類載入器類(上文描述)
- Common 類載入器類(上文描述)
如果 Web 應用程式類載入器配置為 <Loader delegate="true"/>
,則順序變為:
- JVM 的 Bootstrap 類
- System 類載入器類(上文描述)
- Common 類載入器類(上文描述)
- 您的 Web 應用程式的 /WEB-INF/classes
- 您的 Web 應用程式的 /WEB-INF/lib/*.jar
XML解析器和Java
在舊版本的Tomcat中,您可以簡單地替換Tomcat庫目錄中的XML解析器,以更改所有Web應用程式使用的解析器。然而,在執行現代版本的Java時,這種技術將不會有效,因為通常的類載入器委託過程總是會優先選擇JDK內部的實現,而不是這個解析器。
Java支援一種稱為可升級模組的機制,允許替換在JCP之外建立的API(即W3C的DOM和SAX)。它還可以用於更新XML解析器的實現。
請注意,覆蓋任何JRE元件都存在風險。如果覆蓋元件不提供100%相容的API(例如,Xerces提供的API與JRE提供的XML API不完全相容),那麼Tomcat和/或部署的應用程式可能會遇到錯誤。
高階配置
還可以配置更復雜的類載入器層次結構。請參見下面的圖表。預設情況下,伺服器和共享類載入器未定義,並且使用上面顯示的簡化層次結構。可以透過在 conf/catalina.properties 中定義 server.loader 和/或 shared.loader 屬性的值來使用此更復雜的層次結構。
Bootstrap
|
System
|
Common
/ \
Server Shared
/ \
Webapp1 Webapp2 ...
伺服器類載入器僅對Tomcat內部可見,對Web應用程式完全不可見。
共享類載入器對所有Web應用程式可見,可用於在所有Web應用程式之間共享程式碼。但是,對此共享程式碼的任何更新都將需要重新啟動Tomcat。
參考資料
https://tomcat.apache.org/tomcat-11.0-doc/class-loader-howto.html