昨天,看一個build Standalone中databrusher的一個腳本,發(fā)現(xiàn)一個Java類似乎沒有在classpath中,好像也可一直運行了。很疑惑,問了對應的開發(fā)同學,然后自己好好看了下它的代碼,才知道了原理。
命令是:$JAVA_HOME/bin/java $JAVA_OPTS com.alibaba.standalone.AppStartor com.alibaba.intl.standalone.databrusher.Startor "$main_class" "$signal_file" "$recivers"
原理是:Java根據(jù)classpath找到,com.alibaba.standalone.AppStartor這個class,運行這個class,會啟動一個classloader來加載com.alibaba.intl.standalone.databrusher.Startor(在里面會指定到WORLDS-INF目錄下加載類),然后com.alibaba.intl.standalone.databrusher.Startor會啟動對應的"$main_class".
然后,花了挺多時間好好看了一下Java的classloader,了解一下其中的原理和看了下代碼。下面也簡單總結一下吧。
java虛擬機是由sun.misc.Launcher來初始化的,也就是java(或java.exe)這個程序來做的.虛擬機按以下順序搜索并裝載所有需要的類:
1,引導類:組成java平臺的類,包含rt.jar和i18n.jar等基礎jar包中的類.
2,擴展類:使用java擴展機制的類,都是位于擴展目錄($JAVA_HOME/jre/lib/ext)中的.jar檔案包.
3,用戶類:開發(fā)者定義的類或者沒有使用java擴展機制的第三方產(chǎn)品.你必須在命令行中使用-classpath選項或者使用CLASSPATH環(huán)境變量來確定這些類的位,或者自己寫ClassLoader加載。
Java的class loader的大致情況如下圖所示:
http://renyongjie668.blog.163.com/prevPhDownload.do?host=renyongjie668&albumId=197449439&photoId=6568564371
bootstrap classloader -->extension classloader-->system classloader
虛擬機一啟動,會先做一些初始化的動作。一旦初始化動作完成之后,就會 產(chǎn)生第一個類別加載器,即所謂的Bootstrap Loader,Bootstrap Loader 是由C++ 所撰寫而成,這個Bootstrap Loader所做的初始工作中,除了也做一些基本的初始化動作之外,最重要的就是加載定義在sun.misc 命名空間底下的Launcher.java 之中的ExtClassLoader( 因為是inner class ,所以編譯之后會變成Launcher$ExtClassLoader.class) ,并設定其Parent 為null,代表其父加載器為Bootstrap Loader 。然后Bootstrap Loader ,再要求加載定義于sun.misc 命名空間底下的Launcher.java 之中的AppClassLoader( 因為是inner class,所以編譯之后會變成Launcher$AppClassLoader.class) ,并設定其Parent 為之前產(chǎn)生的ExtClassLoader 實例。
a. Bootstrap ClassLoader/啟動類加載器
主要負責java_home/jre/lib目錄下的核心 api 或 -Xbootclasspath 選項指定的jar包裝入工作.
b. Extension ClassLoader/擴展類加載器
主要負責java_home/jre/lib/ext目錄下的jar包或 -Djava.ext.dirs 指定目錄下的jar包裝入工作
c. System ClassLoader/系統(tǒng)類加載器
主要負責java -classpath/-Djava.class.path或$CLASSPATH變量所指的目錄下的類與jar包裝入工作.(這里需要說明的是,如果$CLASSPATH為空,jdk會默認將被運行的Java類的當前路徑作為一個默認的$CLASSPATH,一但設置了$CLASSPATH變量,則會到$CLASSPATH對應的路徑下去尋找相應的類,找不到就會報錯。這個結論,我已經(jīng)經(jīng)過測試,并且看了下類加載器中源代碼)
d. User Custom ClassLoader/用戶自定義類加載類(java.lang.ClassLoader的子類)在程序運行期間, 通過java.lang.ClassLoader的子類動態(tài)加載class文件, 體現(xiàn)java動態(tài)實時類裝入特性.
為了有更多的了解,寫了個簡單的Java程序對前面三種classloader能加載類的路徑及其parent類進行了測試。代碼如下:
import java.net.URL;
import java.net.URLClassLoader;
/**
* @className: IClassLoader
* @description: 測試三種classloader加載類的路徑,及其parent
* @author: 笑遍世界
* @createTime: 2010-11-17 下午07:33:40
*/
public class IClassLoader {
public static void main(String[] args) {
// 測試bootstrap classloader 的類加載路徑
URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs();
for (int i = 0; i < urls.length; i++) {
System.out.println(urls[i].toExternalForm());
}
// 測試extension classloader 的類加載路徑,先打印一個路徑,再打印出其parent,然后再打印出類加載路徑中的所有jar包
System.out.println("-------------------------------------");
System.out.println(System.getProperty("java.ext.dirs"));
ClassLoader extensionClassloader=ClassLoader.getSystemClassLoader().getParent();
System.out.println("the parent of extension classloader : "+extensionClassloader.getParent());
System.out.println("extension classloader can use thess jars:");
URL[] extURLs = ((URLClassLoader)ClassLoader.getSystemClassLoader().getParent()).getURLs();
for (int i = 0; i < extURLs.length; i++) {
System.out.println(extURLs[i]);
}
// 測試system classloader 的類加載路徑,其實也就時classpath的路徑,并打印出它的parent
System.out.println("-------------------------------------");
System.out.println(System.getProperty("java.class.path"));
System.out.println(ClassLoader.getSystemResource(""));
ClassLoader systemClassloader=ClassLoader.getSystemClassLoader();
System.out.println("the parent of system classloader : "+systemClassloader.getParent());
}
}
本機(linux+jdk1.5)運行結果如下:
file:/usr/ali/java/jre/lib/rt.jar
file:/usr/ali/java/jre/lib/i18n.jar
file:/usr/ali/java/jre/lib/sunrsasign.jar
file:/usr/ali/java/jre/lib/jsse.jar
file:/usr/ali/java/jre/lib/jce.jar
file:/usr/ali/java/jre/lib/charsets.jar
file:/usr/ali/java/jre/classes
-------------------------------------
/usr/ali/java/jre/lib/ext
the parent of extension classloader : null
extension classloader can use thess jars:
file:/usr/ali/java/jre/lib/ext/emma.jar
file:/usr/ali/java/jre/lib/ext/localedata.jar
file:/usr/ali/java/jre/lib/ext/dnsns.jar
file:/usr/ali/java/jre/lib/ext/sunpkcs11.jar
file:/usr/ali/java/jre/lib/ext/sunjce_provider.jar
-------------------------------------
.:/usr/ali/java/lib/dt.jar:/usr/ali/java/lib/tools.jar
file:/home/master/workspace/2010_11/bin/
the parent of system classloader : sun.misc.Launcher$ExtClassLoader@1a5ab41
//ps:當前路徑.即是/home/master/workspace/2010_11/bin/
關于Java的classloader其原理還是需要好好理解才能清楚的,僅通過一天的了解,記錄為上面那么多吧。更多詳細信息,可以參考如下資料:
http://snandy.javaeye.com/blog/307083
http://haofenglemon.javaeye.com/blog/426382
http://blog.csdn.net/zdwzzu2006/archive/2008/04/05/2253982.aspx
http://wuquanyin1011.javaeye.com/blog/703842
http://hi.baidu.com/yangzhibin_bai/blog/item/78846cce1cb86b0992457ead.html
http://www.tkk7.com/clraychen/archive/2008/02/20/180868.html