日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Java虛擬機(jī)學(xué)習(xí)(10):類加載器(ClassLoader)

 冬O_O煦 2016-11-19


來(lái)源:java2000_wl

鏈接:blog.csdn.net/java2000_wl/article/details/8222876


類加載器(ClassLoader)用來(lái)加載 class字節(jié)碼到 Java 虛擬機(jī)中。一般來(lái)說(shuō),Java 虛擬機(jī)使用 Java 類的方式如下:Java 源文件在經(jīng)過(guò) Javac之后就被轉(zhuǎn)換成 Java 字節(jié)碼文件(.class 文件)。類加載器負(fù)責(zé)讀取 Java 字節(jié)代碼,并轉(zhuǎn)換成 java.lang.Class 類的一個(gè)實(shí)例。每一個(gè)這樣的實(shí)例用來(lái)表示一個(gè) Java 類。實(shí)際的情況可能更加復(fù)雜,比如 Java 字節(jié)代碼可能是通過(guò)工具動(dòng)態(tài)生成的,也可能是通過(guò)網(wǎng)絡(luò)下載。


類與類加載器


類加載器雖然只用于實(shí)現(xiàn)類的加載動(dòng)作,但它在Java程序中起到的作用卻遠(yuǎn)遠(yuǎn)不限于類加載階段。對(duì)于任意一個(gè)類,都需要由加載它的類加載器和這個(gè)類本身一同確立其在Java虛擬中的唯一性。說(shuō)通俗一些,比較兩個(gè)類是否“相等”,只有在兩個(gè)類是由同一個(gè)類加載器的前提之下才有意義,否則,即使這兩個(gè)類來(lái)源于同一個(gè)class文件,只要加載它的類加載器不同,那這兩個(gè)類必定不相等。這里所指的“相等”包括代表類的Class對(duì)象的equal方法、isAssignableFrom()、isInstance()方法及instance關(guān)鍵字返回的結(jié)果。


類加載器分類:



主要分為Bootstrap ClassLoader、Extension ClassLoader、Application ClassLoader和User Defined ClassLoader。


啟動(dòng)類加載器(Bootstrap ClassLoader):


這個(gè)類加載器使用C++語(yǔ)言實(shí)現(xiàn),并非ClassLoader的子類。主要負(fù)責(zé)加載存放在JAVA_HOME /  jre /  lib / rt.jar里面所有的class文件,或者被-Xbootclasspath參數(shù)所指定路徑中以rt.jar命名的文件。


擴(kuò)展類加載器(Extension ClassLoader):


這個(gè)加載器由sun.misc.Launcher$ExtClassLoader實(shí)現(xiàn),它負(fù)責(zé)加載AVA_HOME /  lib / ext目錄中的,或者被java.ext.dirs系統(tǒng)變量所指定的路徑中的所有類庫(kù)。


應(yīng)用程序類加載器(Application ClassLoader):


這個(gè)加載器由sun.misc.Launcher$AppClassLoader實(shí)現(xiàn),它負(fù)責(zé)加載classpath對(duì)應(yīng)的jar及目錄。一般情況下這個(gè)就是程序中默認(rèn)的類加載器。


自定義類加載器(User Defined ClassLoader):


開(kāi)發(fā)人員繼承ClassLoader抽象類自行實(shí)現(xiàn)的類加載器,基于自行開(kāi)發(fā)的ClassLoader可用于并非加載classpath中(例如從網(wǎng)絡(luò)上下載的jar或二進(jìn)制字節(jié)碼)、還可以在加載class文件之前做些小動(dòng)作 如:加密等。


雙親委托模型:


上圖中所展示的類加載器之間的這種層次關(guān)系,就稱為類加載器的雙親委托模型。雙親委托模型要求除了頂層的啟動(dòng)類加載器外,其余的類加載器都應(yīng)當(dāng)有自己的父類加載器。這里類加載器之間的父子關(guān)系一般不會(huì)以繼承的關(guān)系來(lái)實(shí)現(xiàn),而是使用組合關(guān)系來(lái)復(fù)用父加載器的代碼。


public abstract class ClassLoader {  

 

    private static native void registerNatives();  

    static {  

        registerNatives();  

    }  

 

    // The parent class loader for delegation  

    private ClassLoader parent;  

 

    // Hashtable that maps packages to certs  

    private Hashtable package2certs = new Hashtable(11);  

}


雙親委托的工作過(guò)程:如果一個(gè)類加載器收到了一個(gè)類加載請(qǐng)求,它首先不會(huì)自己去加載這個(gè)類,而是把這個(gè)請(qǐng)求委托給父類加載器去完成,每一個(gè)層次的類加載器都是如此,因此所有的加載請(qǐng)求最終都應(yīng)該傳送到頂層的啟動(dòng)類加載器中,只有當(dāng)父類加載器反饋?zhàn)约簾o(wú)法完成加載請(qǐng)求(它管理的范圍之中沒(méi)有這個(gè)類)時(shí),子加載器才會(huì)嘗試著自己去加載。


使用雙親委托模型來(lái)組織類加載器之間的關(guān)系,有一個(gè)顯而易見(jiàn)的好處就是Java類隨著它的類加載器一起具備了一種帶有優(yōu)先級(jí)的層次關(guān)系,例如java.lang.Object存放在rt.jar之中,無(wú)論那個(gè)類加載器要加載這個(gè)類,最終都是委托給啟動(dòng)類加載器進(jìn)行加載,因此Object類在程序的各種類加載器環(huán)境中都是同一個(gè)類,相反,如果沒(méi)有雙親委托模型,由各個(gè)類加載器去完成的話,如果用戶自己寫(xiě)一個(gè)名為java.lang.Object的類,并放在classpath中,應(yīng)用程序中可能會(huì)出現(xiàn)多個(gè)不同的Object類,java類型體系中最基本安全行為也就無(wú)法保證。


類加載器SPI:


java.lang.ClassLoader 類提供的幾個(gè)關(guān)鍵方法:


loadClass: 此方法負(fù)責(zé)加載指定名字的類,首先會(huì)從已加載的類中去尋找,如果沒(méi)有找到;從parent ClassLoader[ExtClassLoader]中加載;如果沒(méi)有加載到,則從Bootstrap ClassLoader中嘗試加載(findBootstrapClassOrNull方法), 如果還是加載失敗,則拋出異常ClassNotFoundException, 在調(diào)用自己的findClass方法進(jìn)行加載。如果要改變類的加載順序可以覆蓋此方法;如果加載順序相同,則可以通過(guò)覆蓋findClass方法來(lái)做特殊處理,例如:解密,固定路徑尋找等。當(dāng)通過(guò)整個(gè)尋找類的過(guò)程仍然未獲取Class對(duì)象,則拋出ClassNotFoundException異常。


如果類需要resolve,在調(diào)用resolveClass進(jìn)行鏈接。


  protected synchronized Class loadClass(String name, boolean resolve)  

throws ClassNotFoundException  

   {  

// First, check if the class has already been loaded  

Class c = findLoadedClass(name);  

if (c == null) {  

    try {  

    if (parent != null) {  

        c = parent.loadClass(name, false);  

    } else {  

        c = findBootstrapClassOrNull(name);  

    }  

    } catch (ClassNotFoundException e) {  

               // ClassNotFoundException thrown if class not found  

               // from the non-null parent class loader  

           }  

           if (c == null) {  

        // If still not found, then invoke findClass in order  

        // to find the class.  

        c = findClass(name);  

    }  

}  

if (resolve) {  

    resolveClass(c);  

}  

return c;  

   }


findLoadedClass 此方法負(fù)責(zé)從當(dāng)前ClassLoader實(shí)例對(duì)象的緩存中尋找已加載的類,調(diào)用的為native方法。


protected final Class findLoadedClass(String name) {  

(!checkName(name))  

 return null;  

urn findLoadedClass0(name);  

}  

 

private native final Class findLoadedClass0(String name);


findClass 此方法直接拋出ClassNotFoundException異常,因此要通過(guò)覆蓋loadClass或此方法來(lái)以自定義的方式加載相應(yīng)的類。


protected Class findClass(String name) throws ClassNotFoundException {  

ow new ClassNotFoundException(name);  

}


findSystemClass  此方法是從sun.misc.Launcher$AppClassLoader中尋找類,如果未找到,則繼續(xù)從BootstrapClassLoader中尋找,如果仍然未找到,返回null


   protected final Class findSystemClass(String name)  

throws ClassNotFoundException  

   {  

ClassLoader system = getSystemClassLoader();  

if (system == null) {  

    if (!checkName(name))  

    throw new ClassNotFoundException(name);  

           Class cls = findBootstrapClass(name);  

           if (cls == null) {  

               throw new ClassNotFoundException(name);  

           }   

    return cls;  

}  

return system.loadClass(name);  

   }


defineClass 此方法負(fù)責(zé)將二進(jìn)制字節(jié)流轉(zhuǎn)換為Class對(duì)象,這個(gè)方法對(duì)于自定義類加載器而言非常重要。如果二進(jìn)制的字節(jié)碼的格式不符合jvm class文件格式規(guī)范,則拋出ClassFormatError異常;如果生成的類名和二進(jìn)制字節(jié)碼不同,則拋出NoClassDefFoundError;如果加載的class是受保護(hù)的、采用不同簽名的,或者類名是以java.開(kāi)頭的,則拋出SecurityException異常。


protected final Class defineClass(String name, byte[] b, int off, int len,  

                     ProtectionDomain protectionDomain)  

    throws ClassFormatError  

    {  

         return defineClassCond(name, b, off, len, protectionDomain, true);  

    }  

 

    // Private method w/ an extra argument for skipping class verification  

    private final Class defineClassCond(String name,  

                                           byte[] b, int off, int len,  

                                           ProtectionDomain protectionDomain,  

                                           boolean verify)  

        throws ClassFormatError  

    {  

    protectionDomain = preDefineClass(name, protectionDomain);  

 

    Class c = null;  

        String source = defineClassSourceLocation(protectionDomain);  

 

    try {  

        c = defineClass1(name, b, off, len, protectionDomain, source,  

                             verify);  

    } catch (ClassFormatError cfe) {  

        c = defineTransformedClass(name, b, off, len, protectionDomain, cfe,  

                                       source, verify);  

    }  

 

    postDefineClass(c, protectionDomain);  

    return c;  

    }


resolveClass 此方法負(fù)責(zé)完成Class對(duì)象的鏈接,如果鏈接過(guò),則直接返回。


常見(jiàn)異常:


ClassNotFoundException  這是最常見(jiàn)的異常,產(chǎn)生這個(gè)異常的原因?yàn)樵诋?dāng)前的ClassLoader 中加載類時(shí),未找到類文件,


NoClassDefFoundError  這個(gè)異常是因?yàn)? 加載到的類中引用到的另外類不存在,例如要加載A,而A中盜用了B,B不存在或當(dāng)前的ClassLoader無(wú)法加載B,就會(huì)拋出這個(gè)異常。


LinkageError 該異常在自定義ClassLoader的情況下更容易出現(xiàn),主要原因是此類已經(jīng)在ClassLoader加載過(guò)了,重復(fù)的加載會(huì)造成該異常。


本系列:



關(guān)注「ImportNew」

看更多 Java 技術(shù)精選文章

↓↓

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多