Java虛擬機探險之Class Loader

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

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

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

          這次我們只討論JVMClass Loader,下次再討論JVM的內存管理。

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

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

          1.       繼承關系

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

          2.       代理關系

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

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

          當然如果被請求的類已經加載到了內存中,就不會觸發這個查找過程了,而是直接返回已經加載的類。

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


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

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

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

          3.       同一繼承鏈可見性

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

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

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

          4.       多個繼承鏈不可見性

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

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

          理解了Class Loader所具有的特點,我們來看看JDK中都預置了哪些Class Loader。也是JVM啟動時默認創建的Class Loader。如圖2


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

          一般我們的應用都是通過設置CLASSPATH,最終由App Class Loader來加載。根據Class Loader的繼承關系,我們應用中的類可以訪問JDK的核心類庫。反之則會出錯。

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




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

          1.       JDK App (or System) Class Loader

          l       負責加載WLS啟動腳本中CLASSPATH中設置的類

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

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

          2.       EJB Class Loader (1)

          l       負責加載單獨的EJB jar里的類。

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

          3.       WAR Class Loader (1)

          l       負責加載單獨的WAR里的類

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

          4.       EAR Class Loader

          l       負責加載EAR里面的APP-INF下的類

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

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

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

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

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

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


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


          網站導航:
           

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

          Copyright © 天快黑了

          主站蜘蛛池模板: 金溪县| 留坝县| 大同市| 芦山县| 乐山市| 天门市| 金乡县| 沙坪坝区| 铜陵市| 广南县| 故城县| 隆回县| 镇赉县| 玉山县| 益阳市| 仲巴县| 怀仁县| 乌拉特后旗| 化州市| 尉氏县| 钟祥市| 顺平县| 石楼县| 宝清县| 平顺县| 磴口县| 阿图什市| 科技| 文昌市| 阳信县| 锦州市| 东乡族自治县| 宣化县| 墨脱县| 龙井市| 两当县| 夏津县| 麟游县| 宽城| 兰坪| 西华县|