與很多服務(wù)器應(yīng)用一樣,Tomcat 也安裝了各種類(lèi)加載器(那就是實(shí)現(xiàn)了 java.lang.ClassLoader
的類(lèi))。借助類(lèi)加載器,容器的不同部分以及運(yùn)行在容器上的 Web 應(yīng)用就可以訪問(wèn)不同的倉(cāng)庫(kù)(保存著可使用的類(lèi)和資源)。這個(gè)機(jī)制實(shí)現(xiàn)了 Servlet 規(guī)范 2.4 版(尤其是 9.4 節(jié)和 9.6 節(jié))里所定義的功能。
在 Java 環(huán)境中,類(lèi)加載器的布局結(jié)構(gòu)是一種父子樹(shù)的形式。通常,類(lèi)加載器被請(qǐng)求加載一個(gè)特定的類(lèi)或資源時(shí),它會(huì)先把這一請(qǐng)求委托給它的父類(lèi)加載器,只有(一個(gè)或多個(gè))父類(lèi)加載器無(wú)法找到請(qǐng)求的類(lèi)或資源時(shí),它才開(kāi)始查看自身的倉(cāng)庫(kù)。注意,Web 應(yīng)用的類(lèi)加載器模式跟這個(gè)稍有不同,下文將詳細(xì)介紹,但基本原理是一樣。
當(dāng) Tomcat 啟動(dòng)后,它就會(huì)創(chuàng)建一組類(lèi)加載器,這些類(lèi)加載器被布局成如下圖所示這種父子關(guān)系,父類(lèi)加載器在子類(lèi)加載器之上:
Bootstrap
|
System
|
Common
/ \
Webapp1 Webapp2 ...
接下來(lái),通過(guò)幾節(jié)內(nèi)容來(lái)詳細(xì)說(shuō)明每一個(gè)類(lèi)加載器的特點(diǎn),其中還將講解這些加載器可使用的類(lèi)和資源的來(lái)源。
如上圖所示,Tomcat 在初始化時(shí)會(huì)創(chuàng)建如下這些類(lèi)加載器:
Bootstrap 這種類(lèi)加載器包含 JVM 所提供的基本的運(yùn)行時(shí)類(lèi),以及來(lái)自系統(tǒng)擴(kuò)展目錄($JAVA_HOME/jre/lib/ext
)里 JAR 文件中的類(lèi)。注意:在有些 JVM 的實(shí)現(xiàn)中,它的作用不僅僅是類(lèi)加載器,或者它可能根本不可見(jiàn)(作為類(lèi)加載器)。
System 這種類(lèi)加載器通常是根據(jù) CLASSPATH
環(huán)境變量?jī)?nèi)容進(jìn)行初始化的。所有的這些類(lèi)對(duì)于 Tomcat 內(nèi)部類(lèi)以及 Web 應(yīng)用來(lái)說(shuō)都是可見(jiàn)的。不過(guò),標(biāo)準(zhǔn)的 Tomcat 啟動(dòng)腳本($CATALINA_HOME/bin/catalina.sh
或 %CATALINA_HOME%\bin\catalina.bat
)完全忽略了 CLASSPATH
環(huán)境變量自身的內(nèi)容,相反從下列倉(cāng)庫(kù)來(lái)構(gòu)建系統(tǒng)類(lèi)加載器:
$CATALINA_HOME/bin/bootstrap.jar
包含用來(lái)初始化 Tomcat 服務(wù)器的 main()
方法,以及它所依賴(lài)的類(lèi)加載器實(shí)現(xiàn)類(lèi)。$CATALINA_BASE/bin/tomcat-juli.jar
或 $CATALINA_HOME/bin/tomcat-juli.jar
日志實(shí)現(xiàn)類(lèi)。其中包括了對(duì) java.util.logging
API 的功能增強(qiáng)類(lèi)(Tomcat JULI),以及對(duì) Tomcat 內(nèi)部使用的 Apache Commons 日志庫(kù)的包重命名副本。詳情參看 Tomcat 日志文檔。
如果 *$CATALINA_BASE/bin* 中存在 `tomcat-juli.jar`,就不會(huì)使用 *$CATALINA_HOME/bin* 中的那一個(gè)。它有助于日志的特定配置。
$CATALINA_HOME/bin/commons-daemon.jar
Apache Commons Daemon 項(xiàng)目的類(lèi)。該 JAR 文件并不存在于由 catalina.bat
或 catalina.sh
腳本所創(chuàng)建的 CLASSPATH
中,而是引用自 bootstrap.jar 的清單文件。Common 這種類(lèi)加載器包含更多的額外類(lèi),它們對(duì)于Tomcat 內(nèi)部類(lèi)以及所有 Web 應(yīng)用都是可見(jiàn)的。
通常,應(yīng)用類(lèi)不會(huì)放在這里。該類(lèi)加載器所搜索的位置定義在 $CATALINA_BASE/conf/catalina.properties
的 common.loader
屬性中。默認(rèn)的設(shè)置會(huì)搜索下列位置(按照列表中的上下順序)。
$CATALINA_BASE/lib
中的解包的類(lèi)和資源。$CATALINA_BASE/lib
中的 JAR 文件。$CATALINA_HOME/lib
中的解包類(lèi)和資源。$CATALINA_HOME/lib
中的 JAR 文件。
默認(rèn),它包含以下這些內(nèi)容:
/WEB-INF/classes
目錄中所有的解包類(lèi)及資源,以及 /WEB-INF/lib
目錄下 JAR 文件中的所有類(lèi)及資源,對(duì)于該應(yīng)用而言都是可見(jiàn)的,但對(duì)于其他應(yīng)用來(lái)說(shuō)則不可見(jiàn)。如上所述,Web 應(yīng)用類(lèi)加載器背離了默認(rèn)的 Java 委托模式(根據(jù) Servlet 規(guī)范 2.4 版的 9.7.2 Web Application Classloader一節(jié)中提供的建議)。當(dāng)某個(gè)請(qǐng)求想從 Web 應(yīng)用的 WebappX 類(lèi)加載器中加載類(lèi)時(shí),該類(lèi)加載器會(huì)先查看自己的倉(cāng)庫(kù),而不是預(yù)先進(jìn)行委托處理。There are exceptions。JRE 基類(lèi)的部分類(lèi)不能被重寫(xiě)。對(duì)于一些類(lèi)(比如 J2SE 1.4+ 的 XML 解析器組件),可以使用 J2SE 1.4 支持的特性。最后,類(lèi)加載器會(huì)顯式地忽略所有包含 Servlet API 類(lèi)的 JAR 文件,所以不要在 Web 應(yīng)用包含任何這樣的 JAR 文件。Tomcat 其他的類(lèi)加載器則遵循常用的委托模式。
因此,從 Web 應(yīng)用的角度來(lái)看,加載類(lèi)或資源時(shí),要查看的倉(cāng)庫(kù)及其順序如下:
/WEB-INF/classes
類(lèi)/WEB-INF/lib/*.jar
類(lèi)如果 Web 應(yīng)用類(lèi)加載器配置有 <Loader delegate="true"/>
,則順序變?yōu)椋?/p>
/WEB-INF/classes
類(lèi)/WEB-INF/lib/*.jar
類(lèi)從 Java 1.4 版起,JRE 就包含了一個(gè) JAXP API 的副本和一個(gè) XML 解析器。這對(duì)希望使用自己的 XML 解析器的應(yīng)用產(chǎn)生了一定的影響。
在過(guò)去的 Tomcat 中,你只需在 Tomcat 庫(kù)中簡(jiǎn)單地?fù)Q掉 XML 解析器,就能改變所有 Web 應(yīng)用使用的解析器。但對(duì)于現(xiàn)在版本的 Java 而言,這一技術(shù)并沒(méi)有效果,因?yàn)橥ǔ5念?lèi)加載器委托進(jìn)程往往會(huì)優(yōu)先選擇 JDK 內(nèi)部的實(shí)現(xiàn)。
Java 支持一種叫做“授權(quán)標(biāo)準(zhǔn)覆蓋機(jī)制”,從而能夠替換在 JCP 之外創(chuàng)建的 API(例如 W3C 的 DOM 和 SAX)。它還可以用于更新 XML 解析器實(shí)現(xiàn)。關(guān)于此機(jī)制的詳情,請(qǐng)參看 http://docs.oracle.com/javase/1.5.0/docs/guide/standards/index.html。
為了利用該機(jī)制,Tomcat 在啟動(dòng)容器的命令行中包含了系統(tǒng)屬性設(shè)置 -Djava.endorsed.dirs=$JAVA_ENDORSED_DIRS
。該選項(xiàng)的默認(rèn)值為 $CATALINA_HOME/endorsed
。但要注意,這個(gè) endorsed
目錄并非默認(rèn)創(chuàng)建的。
當(dāng)在安全管理器下運(yùn)行時(shí),類(lèi)被允許加載的位置也是基于策略文件中的內(nèi)容,詳情可查看 安全管理器文檔。
更多建議: