ClassLoader in Tomcat (http://rosonsandy.blogdriver.com/rosonsandy/871539.html)
1 - Tomcat
的類載入器的結構
Tomcat Server
在啟動的時候將構造一個ClassLoader樹,以保證模塊的類庫是私有的
Tomcat Server的ClassLoader結構如下:
??????? +-----------------------------+?
??????? |???????? Bootstrap?????????? |?
??????? |???????????? |???? ??????????|?
??????? |????????? System???????????? |?
??????? |???????????? |?????????????? |?
??????? |????????? Common???????????? |?
??????? |???????? /????? \??????????? |?
??????? |???? Catalina? Shared??????? |?
??????? |?????????????? /??? \??????? |?
????
????|????????? WebApp1? WebApp2?? |?
??????? +-----------------------------+
其中:
- Bootstrap - 載入JVM自帶的類和$JAVA_HOME/jre/lib/ext/*.jar
- System - 載入$CLASSPATH/*.class
- Common - 載入$CATALINA_HOME/common/...,它們對TOMCAT和所有的WEB APP都可見
- Catalina - 載入$CATALINA_HOME/server/...,它們僅對TOMCAT可見,對所有的WEB APP都不可見
- Shared - 載入$CATALINA_HOME/shared/...,它們僅對所有WEB APP可見,對TOMCAT不可見(也不必見)
- WebApp - 載入ContextBase?/WEB-INF/...,它們僅對該WEB APP可見
2 - ClassLoader
的工作原理
每個運行中的線程都有一個成員contextClassLoader,用來在運行時動態地載入其它類
系統默認的contextClassLoader是systemClassLoader,所以一般而言java程序在執行時可以使用JVM自帶的類、$JAVA_HOME/jre/lib/ext/中的類和$CLASSPATH/中的類
可以使用
Thread.currentThread().setContextClassLoader(...);
更改當前線程的contextClassLoader,來改變其載入類的行為
ClassLoader
被組織成樹形,一般的工作原理是:
1) 線程需要用到某個類,于是contextClassLoader被請求來載入該類
2) contextClassLoader請求它的父ClassLoader來完成該載入請求
3) 如果父ClassLoader無法載入類,則contextClassLoader試圖自己來載入
注意
:WebApp?ClassLoader的工作原理和上述有少許不同:
它先試圖自己載入類(在ContextBase?/WEB-INF/...中載入類),如果無法載入,再請求父ClassLoader完成
由此可得:
- 對于WEB APP線程,它的contextClassLoader是WebApp?ClassLoader
- 對于Tomcat Server線程,它的contextClassLoader是CatalinaClassLoader
3 類的查找
ClassLoader類中loadClass方法為缺省實現,用下面的順序查找類:
1、調用findLoadedClass方法來檢查是否已經被加載。如果沒有則繼續下面的步驟。
2、如果當前類裝載器有一個指定的委托父裝載器,則用委托父裝載器的loadClass方法加載類,也就是委托給父裝載器加載相應的類。
3、如果這個類裝載器的委托層級體系沒有一個類裝載器加載該類,則使用類裝載器定位類的特定實現機制,調用findClass方法來查找類。
4?-
部分原代碼分析
4.1 - org/apache/catalina/startup/Bootstrap.java
Bootstrap中定義了三個classloader:commonLoader,catalinaLoader,sharedLoader.三者關系如下:
//
注意三個自己定置的ClassLoader的層次關系:?
???????????
// systemClassLoader (root)?
??
??????????
//?? +--- commonLoader?
???????????
//????????? +--- catalinaLoader?
???????????
//????????? +--- sharedLoader
Tomcat Server
線程的起點
構造ClassLoader樹,通過Thread.currentThread().setContextClassLoader(catalinaLoader)設置當前的classloader為catalinaLoader。
載入若干類,然后轉入org.apache.catalina.startup.Catalina類中
4.2 org.apache.catalina.loader.StandardClassLoader.java
通過看loadClass這個方法來看tomcat是如何加載類的,順序如下:
(0) Check our previously loaded class cache查找已經裝載的class
??????? clazz = findLoadedClass(name);
(1)?If a system class, use system class loader通過系統classloader來裝載class
??????? ClassLoader loader = system;
??????????? clazz = loader.loadClass(name);
(2) Delegate to our parent if requested如果有代理則使用父類classloader
??????????? ClassLoader loader = parent;
??????????? if (loader == null)
??????????????? loader = system;
????????????clazz = loader.loadClass(name);
(3) Search local repositories 查找本地類池,比如$CATALINA_HOME/server
?????????? clazz = findClass(name);
(4) Delegate to parent unconditionally 默認使用代理裝載器
[
查看代碼]
4.3 - org/apache/catalina/startup/ClassLoaderFactory.java
根據設置創建并返回StandardClassLoader的實例
[
查看代碼]
4.4 - org/apache/catalina/loader/StandardClassLoader.java
類載入器
4.5 - org/apache/catalina/startup/SecurityClassLoad.java
該類僅包含一個靜態方法,用來為catalinaLoader載入一些類
[
查看代碼]
Appendix -
參考
[1] http://jakarta.apache.org/tomcat/
中的Tomcat 4.1.x文檔Class Loader HOW-TO
在一個
JVM
中可能存在多個
ClassLoader
,每個
ClassLoader
擁有自己的
NameSpace
。一個
ClassLoader
只能擁有一個
class
對象類型的實例,但是不同的
ClassLoader
可能擁有相同的
class
對象實例,這時可能產生致命的問題。如
ClassLoaderA
,裝載了類
A
的類型實例
A1
,而
ClassLoaderB
,也裝載了類
A
的對象實例
A2
。邏輯上講
A1=A2
,但是由于
A1
和
A2
來自于不同的
ClassLoader
,它們實際上是完全不同的,如果
A
中定義了一個靜態變量
c
,則
c
在不同的
ClassLoader
中的值是不同的。
posted on 2006-04-18 08:48
小小程序程序員混口飯吃 閱讀(450)
評論(0) 編輯 收藏 所屬分類:
java