Java虛擬機探險之Class Loader

          Posted on 2010-08-17 10:47 天快黑了 閱讀(2240) 評論(0)  編輯  收藏 所屬分類: JVM
           

          眾所周知,所有的Java class文件都是由JVM(虛擬機)加載并執(zhí)行的。深入理解JVM對于我們提高Java技術(shù)和解決Java問題都有非常大的幫助。

          JVM內(nèi)部主要包括內(nèi)存管理和Class Loader(類加載器)兩個部分。熟悉了內(nèi)存管理,我們就會清楚程序在內(nèi)存中是怎么分配和執(zhí)行的,就能解決所有和對象相關(guān)的問題(比如Memory Leak)。理解了Class Loader,就能解決所有類找不到(比如遇到NoClassDefFoundErrorClassNotFoundException)或配置文件找不到問題。

          這次我們只討論JVMClass Loader,下次再討論JVM的內(nèi)存管理。

          Class Loader的主要作用就是負(fù)責(zé)查找類并將其加載到內(nèi)存中。有趣的是,Java中的Class Loader也是由Java所寫,就和普通的class一樣。這就產(chǎn)生了一個是雞生蛋還是蛋生雞的問題,到底第一個class由誰來加載呢?我們稍后會來討論這個問題。

          先來看一下Class Loader所具有的特點。

          1.       繼承關(guān)系

          雖然Class Loader也是一個Java class,但這里的繼承不是指定義class時使用的extends關(guān)鍵字來實現(xiàn)的繼承,而是指由屬性來維持的繼承關(guān)系。即通過Class Loader的構(gòu)造方法或其它方法顯式的設(shè)置一個父Class Loader。

          2.       代理關(guān)系

          每一個Class Loader在接到請求去加載一個類之前(默認(rèn),訪問一個類的時候,就會由加載當(dāng)前類的Class Loader去加載被訪問的類),它會首先請求它的父Class Loader來嘗試加載,依次往上,如果父Class Loader加載成功,則直接返回,子Class Loader不再查找。

          否則依次往下查找并加載。如果直到被請求的Class Loader也沒有找到要加載的類,則會出現(xiàn)NoClassDefFoundErrorClassNotFoundException

          當(dāng)然如果被請求的類已經(jīng)加載到了內(nèi)存中,就不會觸發(fā)這個查找過程了,而是直接返回已經(jīng)加載的類。

          我們來看一個例子,假設(shè)有圖1中的Class Loader層次:


          如果我們請求
          Class Loader E去加載Test.class,首先它會請求父Class Loader D去嘗試加載。同樣Class Loader D會先請求它的父Class Loader C去嘗試加載Test.class。當(dāng)然這里Class Loader C找不到Test.class,于是轉(zhuǎn)回由Class Loader D去加載。最終Class Loader D成功找到了D:"Test.class,并將其加載到內(nèi)存中。

          同樣,如果我們請求Class Loader F去加載Test3.class。Class Loader CClass Loader D在各自的搜索范圍內(nèi)都找不到Test3.class。最終會由Class Loader F自己加載F:"Test3.class到內(nèi)存中。

          如果我們請求Class Loader D去加載Test3.class,最終就會出現(xiàn)NoClassDefFoundErrorClassNotFoundException

          3.       同一繼承鏈可見性

          在同一個Class Loader對象的繼承鏈中,下面被加載的類可以訪問上面被加載的類,反之則不可以。

          同樣以圖1為例,Test4.class可以訪問到D:"Test.classC:"Test2.class

          而如果D:"Test.classC:"Test2.class嘗試訪問Test4.class,就會出現(xiàn)NoClassDefFoundErrorClassNotFoundException

          4.       多個繼承鏈不可見性

          多個繼承鏈之間彼此看不到對方,不能相互訪問。

          還以圖1為例,如果Test4.class訪問Test3.class,或反過來Test3.class訪問Test4.class,都會引起NoClassDefFoundErrorClassNotFoundException

          理解了Class Loader所具有的特點,我們來看看JDK中都預(yù)置了哪些Class Loader。也是JVM啟動時默認(rèn)創(chuàng)建的Class Loader。如圖2


          通過圖
          2,我們可以看到Bootstrap Class LoaderJVM中的祖先Class Loader。它是JDK中唯一一個由C++所寫的Class Loader,它負(fù)責(zé)加載JDK的核心類庫(rt.jar)以及另外兩個由Java所寫的Class LoaderExt Class LoaderApp Class Loader)。之后就功成身退,轉(zhuǎn)由Ext Class LoaderApp Class Loader加載所有應(yīng)用中用到的類。

          一般我們的應(yīng)用都是通過設(shè)置CLASSPATH,最終由App Class Loader來加載。根據(jù)Class Loader的繼承關(guān)系,我們應(yīng)用中的類可以訪問JDK的核心類庫。反之則會出錯。

          我們再來看看WebLogicClass Loader的層次關(guān)系(如圖4)。如果需要,大家可以參考一下WebLogicWAREAR的文件結(jié)構(gòu)(如圖3




          WLS
          中自定義了很多新的Class Loader,當(dāng)然他們的祖先Class Loader都是JDK中的App (or System) Class Loader。我們來看一下每個Class Loader的職責(zé)。

          1.       JDK App (or System) Class Loader

          l       負(fù)責(zé)加載WLS啟動腳本中CLASSPATH中設(shè)置的類

          l       所有的類都會最先由它嘗試加載

          l       因為CLASSPATH的值在運行期不允許修改,所以由該Class Loader加載的類在運行期不能被動態(tài)卸載(替換)

          2.       EJB Class Loader (1)

          l       負(fù)責(zé)加載單獨的EJB jar里的類。

          l       不同的EJB jar文件會被不同實例的Class Loader加載,因此EJB jar彼此之間互相看不到對方

          3.       WAR Class Loader (1)

          l       負(fù)責(zé)加載單獨的WAR里的類

          l       不同的WAR文件會被不同實例的Class Loader加載,因此WAR彼此之間互相看不到對方

          4.       EAR Class Loader

          l       負(fù)責(zé)加載EAR里面的APP-INF下的類

          l       不同的EAR文件會被不同實例的EAR Class Loader加載,因此EAR彼此之間互相看不到對方

          l       它下面有一個EJB Class Loader (2) 實例,負(fù)責(zé)加載EAR里面所有的EJB jar。因此,EAR中的EJB彼此之間可以看到對方

          l       EJB Class Loader (2) 下有多個WAR Class Loader (2) 實例。每個實例負(fù)責(zé)加載EAR里面的一個WAR。所以,EAR中的WAR彼此之間看不到對方

          l       根據(jù)繼承鏈規(guī)則,WAR可以看到所有的EJBAPP-INF下的所有類。 EJB可以看到APP-INF下的所有類,但反之則不可以

          Class Loader雖然稱為類加載器,但并不意味著只能用來加載Class,我們還可以利用它來查找圖片和配置文件等資源。比如,我們經(jīng)常使用getClass().getResourceAsStream(name)來查找配置文件。同樣,查找其它資源文件的方式和上面一樣,也會先請求父Class Loader來負(fù)責(zé)查找。

          這里,我們只簡單介紹了Class Loader對于類的查找,而關(guān)于Class Loader的具體加載、校驗和初始化的過程,感興趣的朋友可以參考《深入Java虛擬機》


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           

          posts - 5, comments - 25, trackbacks - 0, articles - 1

          Copyright © 天快黑了

          主站蜘蛛池模板: 尼木县| 东丰县| 彭阳县| 会东县| 潍坊市| 浦城县| 克山县| 理塘县| 肇东市| 七台河市| 九龙县| 山阳县| 南木林县| 射阳县| 宜春市| 建宁县| 大同县| 汾西县| 辽宁省| 凉城县| 玛纳斯县| 乌鲁木齐市| 宜良县| 苍梧县| 沛县| 宁强县| 都昌县| 昌江| 邻水| 休宁县| 安平县| 廉江市| 五峰| 监利县| 博白县| 岑巩县| 福海县| 满城县| 翁牛特旗| 上饶县| 罗源县|