鍍金池/ 教程/ Linux/ 類加載機制
連接器
JSPs
重寫機制
CGI
Tomcat Manager
Windows 認(rèn)證
代理支持
虛擬主機
安全性注意事項
如何在 Maven 中使用 Tomcat 庫
安裝
MBean 描述符
JNDI 資源
類加載機制
Tomcat Web 應(yīng)用部署
基于 APR 的原生庫
負(fù)載均衡器
安全管理
附加組件
監(jiān)控與管理
Windows 服務(wù)
集群化與會話復(fù)制
高級 IO 機制
SSI(服務(wù)器端嵌入)
WebSocket 支持
JDBC 數(shù)據(jù)源
日志機制
默認(rèn) Servlet
SSL/TLS 配置
Tomcat 的 JDBC 連接池
第一個應(yīng)用
簡介
Realm 配置

類加載機制

概述

與很多服務(wù)器應(yīng)用一樣,Tomcat 也安裝了各種類加載器(那就是實現(xiàn)了 java.lang.ClassLoader 的類)。借助類加載器,容器的不同部分以及運行在容器上的 Web 應(yīng)用就可以訪問不同的倉庫(保存著可使用的類和資源)。這個機制實現(xiàn)了 Servlet 規(guī)范 2.4 版(尤其是 9.4 節(jié)和 9.6 節(jié))里所定義的功能。

在 Java 環(huán)境中,類加載器的布局結(jié)構(gòu)是一種父子樹的形式。通常,類加載器被請求加載一個特定的類或資源時,它會先把這一請求委托給它的父類加載器,只有(一個或多個)父類加載器無法找到請求的類或資源時,它才開始查看自身的倉庫。注意,Web 應(yīng)用的類加載器模式跟這個稍有不同,下文將詳細介紹,但基本原理是一樣。

當(dāng) Tomcat 啟動后,它就會創(chuàng)建一組類加載器,這些類加載器被布局成如下圖所示這種父子關(guān)系,父類加載器在子類加載器之上:

      Bootstrap
          |
       System
          |
       Common
       /     \
  Webapp1   Webapp2 ...

接下來,通過幾節(jié)內(nèi)容來詳細說明每一個類加載器的特點,其中還將講解這些加載器可使用的類和資源的來源。

類加載器定義

如上圖所示,Tomcat 在初始化時會創(chuàng)建如下這些類加載器:

  • Bootstrap 這種類加載器包含 JVM 所提供的基本的運行時類,以及來自系統(tǒng)擴展目錄($JAVA_HOME/jre/lib/ext)里 JAR 文件中的類。注意:在有些 JVM 的實現(xiàn)中,它的作用不僅僅是類加載器,或者它可能根本不可見(作為類加載器)。

  • System 這種類加載器通常是根據(jù) CLASSPATH 環(huán)境變量內(nèi)容進行初始化的。所有的這些類對于 Tomcat 內(nèi)部類以及 Web 應(yīng)用來說都是可見的。不過,標(biāo)準(zhǔn)的 Tomcat 啟動腳本($CATALINA_HOME/bin/catalina.sh%CATALINA_HOME%\bin\catalina.bat)完全忽略了 CLASSPATH 環(huán)境變量自身的內(nèi)容,相反從下列倉庫來構(gòu)建系統(tǒng)類加載器:

    • $CATALINA_HOME/bin/bootstrap.jar 包含用來初始化 Tomcat 服務(wù)器的 main() 方法,以及它所依賴的類加載器實現(xiàn)類。
    • $CATALINA_BASE/bin/tomcat-juli.jar$CATALINA_HOME/bin/tomcat-juli.jar 日志實現(xiàn)類。其中包括了對 java.util.logging API 的功能增強類(Tomcat JULI),以及對 Tomcat 內(nèi)部使用的 Apache Commons 日志庫的包重命名副本。詳情參看 Tomcat 日志文檔

      如果 *$CATALINA_BASE/bin* 中存在 `tomcat-juli.jar`,就不會使用 *$CATALINA_HOME/bin* 中的那一個。它有助于日志的特定配置。   
    • $CATALINA_HOME/bin/commons-daemon.jar Apache Commons Daemon 項目的類。該 JAR 文件并不存在于由 catalina.batcatalina.sh 腳本所創(chuàng)建的 CLASSPATH 中,而是引用自 bootstrap.jar 的清單文件。
  • Common 這種類加載器包含更多的額外類,它們對于Tomcat 內(nèi)部類以及所有 Web 應(yīng)用都是可見的。

    通常,應(yīng)用類不會放在這里。該類加載器所搜索的位置定義在 $CATALINA_BASE/conf/catalina.propertiescommon.loader 屬性中。默認(rèn)的設(shè)置會搜索下列位置(按照列表中的上下順序)。

    • $CATALINA_BASE/lib 中的解包的類和資源。
    • $CATALINA_BASE/lib 中的 JAR 文件。
    • $CATALINA_HOME/lib 中的解包類和資源。
    • $CATALINA_HOME/lib 中的 JAR 文件。

      默認(rèn),它包含以下這些內(nèi)容:

    • annotations-api.jar JavaEE 注釋類。
    • catalina.jar Tomcat 的 Catalina servlet 容器部分的實現(xiàn)。
    • catalina-ant.jar Tomcat Catalina Ant 任務(wù)。
    • catalina-ha.jar 高可用性包。
    • catalina-storeconfig.jar
    • catalina-tribes.jar 組通信包
    • ecj-*.jar Eclipse JDT Java 編譯器
    • el-api.jar EL 3.0 API
    • jasper.jar Tomcat Jasper JSP 編譯器與運行時
    • jasper-el.jar Tomcat Jasper EL 實現(xiàn)
    • jsp-api.jar JSP 2.3 API
    • servlet-api.jar Servlet 3.1 API
    • tomcat-api.jar Tomcat 定義的一些接口
    • tomcat-coyote.jar Tomcat 連接器與工具類。
    • tomcat-dbcp.jar 數(shù)據(jù)庫連接池實現(xiàn),基于 Apache Commons Pool 的包重命名副本和 Apache Commons DBCP。
    • tomcat-i18n-**.jar 包含其他語言資源束的可選 JAR。因為默認(rèn)的資源束也可以包含在每個單獨的 JAR 文件中,所以如果不需要國際化信息,可以將其安全地移除。
    • tomcat-jdbc.jar 一個數(shù)據(jù)庫連接池替代實現(xiàn),又被稱作 Tomcat JDBC 池。詳情參看 JDBC 連接池文檔
    • tomcat-util.jar Apache Tomcat 多種組件所使用的常用類。
    • tomcat-websocket.jar WebSocket 1.1 實現(xiàn)
    • websocket-api.jar WebSocket 1.1 API
  • WebappX 為每個部署在單個 Tomcat 實例中的 Web 應(yīng)用創(chuàng)建的類加載器。你的 Web 應(yīng)用的 /WEB-INF/classes 目錄中所有的解包類及資源,以及 /WEB-INF/lib 目錄下 JAR 文件中的所有類及資源,對于該應(yīng)用而言都是可見的,但對于其他應(yīng)用來說則不可見。

如上所述,Web 應(yīng)用類加載器背離了默認(rèn)的 Java 委托模式(根據(jù) Servlet 規(guī)范 2.4 版的 9.7.2 Web Application Classloader一節(jié)中提供的建議)。當(dāng)某個請求想從 Web 應(yīng)用的 WebappX 類加載器中加載類時,該類加載器會查看自己的倉庫,而不是預(yù)先進行委托處理。There are exceptions。JRE 基類的部分類不能被重寫。對于一些類(比如 J2SE 1.4+ 的 XML 解析器組件),可以使用 J2SE 1.4 支持的特性。最后,類加載器會顯式地忽略所有包含 Servlet API 類的 JAR 文件,所以不要在 Web 應(yīng)用包含任何這樣的 JAR 文件。Tomcat 其他的類加載器則遵循常用的委托模式。

因此,從 Web 應(yīng)用的角度來看,加載類或資源時,要查看的倉庫及其順序如下:

  • JVM 的 Bootstrap 類
  • Web 應(yīng)用的 /WEB-INF/classes
  • Web 應(yīng)用的 /WEB-INF/lib/*.jar
  • System 類加載器的類(如上所述)
  • Common 類加載器的類(如上所述)

如果 Web 應(yīng)用類加載器配置有 <Loader delegate="true"/>,則順序變?yōu)椋?

  • JVM 的 Bootstrap 類
  • System 類加載器的類(如上所述)
  • Common 類加載器的類(如上所述)
  • Web 應(yīng)用的 /WEB-INF/classes
  • Web 應(yīng)用的 /WEB-INF/lib/*.jar

XML解析器和 Java

從 Java 1.4 版起,JRE 就包含了一個 JAXP API 的副本和一個 XML 解析器。這對希望使用自己的 XML 解析器的應(yīng)用產(chǎn)生了一定的影響。

在過去的 Tomcat 中,你只需在 Tomcat 庫中簡單地?fù)Q掉 XML 解析器,就能改變所有 Web 應(yīng)用使用的解析器。但對于現(xiàn)在版本的 Java 而言,這一技術(shù)并沒有效果,因為通常的類加載器委托進程往往會優(yōu)先選擇 JDK 內(nèi)部的實現(xiàn)。

Java 支持一種叫做“授權(quán)標(biāo)準(zhǔn)覆蓋機制”,從而能夠替換在 JCP 之外創(chuàng)建的 API(例如 W3C 的 DOM 和 SAX)。它還可以用于更新 XML 解析器實現(xiàn)。關(guān)于此機制的詳情,請參看 http://docs.oracle.com/javase/1.5.0/docs/guide/standards/index.html。

為了利用該機制,Tomcat 在啟動容器的命令行中包含了系統(tǒng)屬性設(shè)置 -Djava.endorsed.dirs=$JAVA_ENDORSED_DIRS。該選項的默認(rèn)值為 $CATALINA_HOME/endorsed。但要注意,這個 endorsed 目錄并非默認(rèn)創(chuàng)建的。

安全管理器下運行

當(dāng)在安全管理器下運行時,類被允許加載的位置也是基于策略文件中的內(nèi)容,詳情可查看 安全管理器文檔。