<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Leo's Blog

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      13 隨筆 :: 3 文章 :: 18 評論 :: 0 Trackbacks

    作者:劉學超

    一、引言

    Java虛擬機(JVM)的類裝載就是指將包含在類文件中的字節(jié)碼裝載到JVM中, 并使其成為JVM一部分的過程。JVM的類動態(tài)裝載技術能夠在運行時刻動態(tài)地加載或者替換系統(tǒng)的某些功能模塊, 而不影響系統(tǒng)其他功能模塊的正常運行。本文將分析JVM中的類裝載系統(tǒng),探討JVM中類裝載的原理、實現(xiàn)以及應用。

    二、Java虛擬機的類裝載實現(xiàn)與應用

    2.1  裝載過程簡介

    所謂裝載就是尋找一個類或是一個接口的二進制形式并用該二進制形式來構造代表這個類或是這個接口的class對象的過程,其中類或接口的名稱是給定了的。當然名稱也可以通過計算得到,但是更常見的是通過搜索源代碼經(jīng)過編譯器編譯后所得到的二進制形式來構造。

    在Java中,類裝載器把一個類裝入Java虛擬機中,要經(jīng)過三個步驟來完成:裝載、鏈接和初始化,其中鏈接又可以分成校驗、準備和解析三步,除了解析外,其它步驟是嚴格按照順序完成的,各個步驟的主要工作如下:

    • 裝載:查找和導入類或接口的二進制數(shù)據(jù);
    • 鏈接:執(zhí)行下面的校驗、準備和解析步驟,其中解析步驟是可以選擇的;
    • 校驗:檢查導入類或接口的二進制數(shù)據(jù)的正確性;
    • 準備:給類的靜態(tài)變量分配并初始化存儲空間;
    • 解析:將符號引用轉成直接引用;
    • 初始化:激活類的靜態(tài)變量的初始化Java代碼和靜態(tài)Java代碼塊。

    至于在類裝載和虛擬機啟動的過程中的具體細節(jié)和可能會拋出的錯誤,請參看《Java虛擬機規(guī)范》以及《深入Java虛擬機》,它們在網(wǎng)絡上面的資源地址是: http://java.sun.com/docs/books/vmspec/2nd-edition/html/Preface.doc.htmlhttp://www.artima.com/insidejvm/ed2/index.html。 由于本文的討論重點不在此就不再多敘述。

    2.2  裝載的實現(xiàn)

    JVM中類的裝載是由ClassLoader和它的子類來實現(xiàn)的,Java ClassLoader 是一個重要的Java運行時系統(tǒng)組件。它負責在運行時查找和裝入類文件的類。

    在Java中,ClassLoader是一個抽象類,它在包java.lang中,可以這樣說,只要了解了在 ClassLoader中的一些重要的方法,再結合上面所介紹的JVM中類裝載的具體的過程,對動態(tài)裝載類這項技術就有了一個比較大概的掌握,這些重要的 方法包括以下幾個:

    ①loadCass方法  loadClass(String name ,boolean resolve)其中name參數(shù)指定了JVM需要的類的名稱,該名稱以包表示法表示,如Java.lang.Object;resolve參數(shù)告訴方法 是否需要解析類,在初始化類之前,應考慮類解析,并不是所有的類都需要解析,如果JVM只需要知道該類是否存在或找出該類的超類,那么就不需要解析。這個 方法是ClassLoader 的入口點。

    ②defineClass方法  這個方法接受類文件的字節(jié)數(shù)組并把它轉換成Class對象。字節(jié)數(shù)組可以是從本地文件系統(tǒng)或網(wǎng)絡裝入的數(shù)據(jù)。它把字節(jié)碼分析成運行時數(shù)據(jù)結構、校驗有效性等等。

    ③findSystemClass方法  findSystemClass方法從本地文件系統(tǒng)裝入文件。它在本地文 件系統(tǒng)中尋找類文件,如果存在,就使用defineClass將字節(jié)數(shù)組轉換成Class對象,以將該文件轉換成類。當運行Java應用程序時,這是 JVM 正常裝入類的缺省機制。

    ④resolveClass方法  resolveClass(Class c)方法解析裝入的類,如果該類已經(jīng)被解析過那么將不做處理。當調(diào)用loadClass方法時,通過它的resolve 參數(shù)決定是否要進行解析。

    ⑤findLoadedClass方法  當調(diào)用loadClass方法裝入類時,調(diào)用 findLoadedClass 方法來查看ClassLoader是否已裝入這個類,如果已裝入,那么返回Class對象,否則返回NULL。如果強行裝載已存在的類,將會拋出鏈接錯 誤。

    2.3  裝載的應用

    一般來說,我們使用虛擬機的類裝載時需要繼承抽象類java.lang.ClassLoader,其中必須實現(xiàn)的方 法是loadClass(),對于這個方法需要實現(xiàn)如下操作:(1) 確認類的名稱;(2) 檢查請求要裝載的類是否已經(jīng)被裝載;(3) 檢查請求加載的類是否是系統(tǒng)類;(4) 嘗試從類裝載器的存儲區(qū)獲取所請求的類;(5) 在虛擬機中定義所請求的類;(6) 解析所請求的類;(7) 返回所請求的類。

    所有的Java 虛擬機都包括一個內(nèi)置的類裝載器,這個內(nèi)置的類庫裝載器被稱為根裝載器(bootstrap ClassLoader)。根裝載器的特殊之處是它只能夠裝載在設計時刻已知的類,因此虛擬機假定由根裝載器所裝載的類都是安全的、可信任的,可以不經(jīng)過 安全認證而直接運行。當應用程序需要加載并不是設計時就知道的類時,必須使用用戶自定義的裝載器(user-defined ClassLoader)。下面我們舉例說明它的應用。

     1 public abstract class MultiClassLoader extends ClassLoader{
     2     
     3     public synchronized Class loadClass(String s, boolean flag)
     4         throws ClassNotFoundException
     5     {
     6         /* 檢查類s是否已經(jīng)在本地內(nèi)存*/
     7         Class class1 = (Class)classes.get(s);
     8 
     9         /* 類s已經(jīng)在本地內(nèi)存*/
    10         if(class1 != null)  return class1; 
    11         try/*用默認的ClassLoader 裝入類*/  {
    12             class1 = super.findSystemClass(s);
    13             return class1;
    14         }
    15         catch(ClassNotFoundException _ex)  {
    16             System.out.println(">> Not a system class.");
    17         }
    18 
    19         /* 取得類s的字節(jié)數(shù)組*/
    20         byte abyte0[] = loadClassBytes(s);
    21         if(abyte0 == null)   throw new ClassNotFoundException();
    22 
    23         /* 將類字節(jié)數(shù)組轉換為類*/
    24         class1 = defineClass(null, abyte0, 0, abyte0.length);
    25         if(class1 == nullthrow new ClassFormatError();
    26         if(flag)   resolveClass(class1); /*解析類*/
    27 
    28         /* 將新加載的類放入本地內(nèi)存*/
    29         classes.put(s, class1);
    30         System.out.println(">> Returning newly loaded class.");
    31 
    32         /* 返回已裝載、解析的類*/
    33         return class1;
    34     }
    35     
    36 }

    三、Java虛擬機的類裝載原理

    前面我們已經(jīng)知道,一個Java應用程序使用兩種類型的類裝載器:根裝載器(bootstrap)和用戶定義的裝載 器(user-defined)。根裝載器是Java虛擬機實現(xiàn)的一部分,舉個例子來說,如果一個Java虛擬機是在現(xiàn)在已經(jīng)存在并且正在被使用的操作系 統(tǒng)的頂部用C程序來實現(xiàn)的,那么根裝載器將是那些C程序的一部分。根裝載器以某種默認的方式將類裝入,包括那些Java API的類。在運行期間一個Java程序能安裝用戶自己定義的類裝載器。根裝載器是虛擬機固有的一部分,而用戶定義的類裝載器則不是,它是用Java語言 寫的,被編譯成class文件之后然后再被裝入到虛擬機,并像其它的任何對象一樣可以被實例化。 Java類裝載器的體系結構如下所示:

    圖1  Java的類裝載的體系結構

    Java的類裝載模型是一種代理(delegation)模型。當JVM 要求類裝載器CL(ClassLoader)裝載一個類時,CL首先將這個類裝載請求轉發(fā)給他的父裝載器。只有當父裝載器沒有裝載并無法裝載這個類時, CL才獲得裝載這個類的機會。這樣, 所有類裝載器的代理關系構成了一種樹狀的關系。樹的根是類的根裝載器(bootstrap ClassLoader) , 在JVM 中它以"null"表示。除根裝載器以外的類裝載器有且僅有一個父裝載器。在創(chuàng)建一個裝載器時, 如果沒有顯式地給出父裝載器, 那么JVM將默認系統(tǒng)裝載器為其父裝載器。Java的基本類裝載器代理結構如圖2所示:

    圖2  Java類裝載的代理結構

    下面針對各種類裝載器分別進行詳細的說明。

    根(Bootstrap) 裝載器:該裝載器沒有父裝載器,它是JVM實現(xiàn)的一部分,從sun.boot.class.path裝載運行時庫的核心代碼。

    擴展(Extension) 裝載器:繼承的父裝載器為根裝載器,不像根裝載器可能與運行時的操作系統(tǒng)有關,這個類裝載器是用純Java代碼實現(xiàn)的,它從java.ext.dirs (擴展目錄)中裝載代碼。

    系統(tǒng)(System or Application) 裝載器:裝載器為擴展裝載器,我們都知道在安裝JDK的時候要設置環(huán)境變量(CLASSPATH ),這個類裝載器就是從java.class.path(CLASSPATH 環(huán)境變量)中裝載代碼的,它也是用純Java代碼實現(xiàn)的,同時還是用戶自定義類裝載器的缺省父裝載器。

    小應用程序(Applet) 裝載器: 裝載器為系統(tǒng)裝載器,它從用戶指定的網(wǎng)絡上的特定目錄裝載小應用程序代碼。

    在設計一個類裝載器的時候,應該滿足以下兩個條件:

    1. 對于相同的類名,類裝載器所返回的對象應該是同一個類對象
    2. 如果類裝載器CL1將裝載類C的請求轉給類裝載器CL2,那么對于以下的類或接口,CL1和CL2應該返回同一個類對象:a)S為C的 直接超類;b)S為C的直接超接口;c)S為C的成員變量的類型;d)S為C的成員方法或構建器的參數(shù)類型;e)S為C的成員方法的返回類型。

    每個已經(jīng)裝載到JVM中的類都隱式含有裝載它的類裝載器的信息。類方法getClassLoader 可以得到裝載這個類的類裝載器。一個類裝載器認識的類包括它的父裝載器認識的類和它自己裝載的類,可見類裝載器認識的類是它自己裝載的類的超集。注意我們 可以得到類裝載器的有關的信息,但是已經(jīng)裝載到JVM中的類是不能更改它的類裝載器的。

    Java中的類的裝載過程也就是代理裝載的過程。比如:Web瀏覽器中的JVM需要裝載一個小應用程序 TestApplet。JVM調(diào)用小應用程序裝載器ACL(Applet ClassLoader)來完成裝載。ACL首先請求它的父裝載器, 即系統(tǒng)裝載器裝載TestApplet是否裝載了這個類, 由于TestApplet不在系統(tǒng)裝載器的裝載路徑中, 所以系統(tǒng)裝載器沒有找到這個類, 也就沒有裝載成功。接著ACL自己裝載TestApplet。ACL通過網(wǎng)絡成功地找到了TestApplet.class 文件并將它導入到了JVM中。在裝載過程中, JVM發(fā)現(xiàn)TestAppet是從超類java.applet.Applet繼承的。所以JVM再次調(diào)用ACL來裝載 java.applet.Applet類。ACL又再次按上面的順序裝載Applet類, 結果ACL發(fā)現(xiàn)他的父裝載器已經(jīng)裝載了這個類, 所以ACL就直接將這個已經(jīng)裝載的類返回給了JVM , 完成了Applet類的裝載。接下來,Applet類的超類也一樣處理。最后, TestApplet及所有有關的類都裝載到了JVM中。

    四、結論

    類的動態(tài)裝載機制是JVM的一項核心技術, 也是容易被忽視而引起很多誤解的地方。本文介紹了JVM中類裝載的原理、實現(xiàn)以及應用,尤其分析了ClassLoader的結構、用途以及如何利用自定義 的ClassLoader裝載并執(zhí)行Java類,希望能使讀者對JVM中的類裝載有一個比較深入的理解。

    轉載自:http://gceclub.sun.com.cn/yuanchuang/week-8/jvm.html

    posted on 2006-02-23 18:31 Leo 閱讀(359) 評論(0)  編輯  收藏 所屬分類: 技術隨文
    主站蜘蛛池模板: 亚洲国产精品网站在线播放| 亚洲一二成人精品区| 91视频免费观看高清观看完整| 久久久久久久91精品免费观看| 日韩精品亚洲人成在线观看| 香港a毛片免费观看| 久久久亚洲精品国产| 无码囯产精品一区二区免费| 日产亚洲一区二区三区| 91人成网站色www免费下载| 最近2019中文字幕免费看最新| 亚洲1区1区3区4区产品乱码芒果| 在线观看www日本免费网站| 亚洲最大免费视频网| 在线精品免费视频| 国产av无码专区亚洲av毛片搜| 亚洲国产成人VA在线观看| 久久久精品视频免费观看| 亚洲国产综合91精品麻豆| 和日本免费不卡在线v| 亚洲Av无码国产一区二区| 亚洲人成影院在线观看| 女同免费毛片在线播放| 亚洲国产精品成人综合久久久| 久久久久久久久免费看无码| 精品久久亚洲一级α| 成人免费午夜在线观看| 亚洲国产成人精品无码区二本| 亚洲精品高清一二区久久| 久久久国产精品无码免费专区| 亚洲成av人片不卡无码| 国产在线观看免费完整版中文版| 亚洲乱妇老熟女爽到高潮的片| 免费h黄肉动漫在线观看| 久久亚洲精品无码av| 国产亚洲成AV人片在线观黄桃| 国产免费不卡视频| xxxxx做受大片在线观看免费| 亚洲人成无码网站久久99热国产| 7x7x7x免费在线观看| 特级aa**毛片免费观看|