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

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

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

    敬的世界

    常用鏈接

    統(tǒng)計(jì)

    最新評(píng)論

    ClassLoader原理

    ?JVM規(guī)范定義了兩種類型的類裝載器:啟動(dòng)內(nèi)裝載器(bootstrap)和用戶自定義裝載器(user-defined class loader)

    一.??? ClassLoader基本概念
    1.ClassLoader分類
    類裝載器是用來(lái)把類(class)裝載進(jìn)JVM的。
    JVM規(guī)范定義了兩種類型的類裝載器:啟動(dòng)內(nèi)裝載器(bootstrap)和用戶自定義裝載器(user-defined class loader)


    JVM在運(yùn)行時(shí)會(huì)產(chǎn)生三個(gè)ClassLoader:Bootstrap?ClassLoader、Extension?ClassLoader和AppClassLoader.Bootstrap是用C++編寫(xiě)的,我們?cè)贘ava中看不到它,是null,是JVM自帶的類裝載器,用來(lái)裝載核心類庫(kù),如java.lang.*等。
    AppClassLoaderParentExtClassLoader,而ExtClassLoaderParentBootstrap?ClassLoader
    ?
    Java提供了抽象類ClassLoader,所有用戶自定義類裝載器都實(shí)例化自ClassLoader的子類。 System Class Loader是一個(gè)特殊的用戶自定義類裝載器,由JVM的實(shí)現(xiàn)者提供,在編程者不特別指定裝載器的情況下默認(rèn)裝載用戶類。系統(tǒng)類裝載器可以通過(guò)ClassLoader.getSystemClassLoader() 方法得到。
    ?
    例1,測(cè)試你所使用的JVM的ClassLoader
    /*LoaderSample1.java*/
    public?class?LoaderSample1?{
    ????
    public?static?void?main(String[]?args)?{
    ????????Class?c;
    ????????ClassLoader?cl;
    ????????cl?
    =?ClassLoader.getSystemClassLoader();
    ????????System.out.println(cl);
    ????????
    while?(cl?!=?null)?{
    ????????????cl?
    =?cl.getParent();
    ????????????System.out.println(cl);
    ????????}
    ????????
    try?{
    ????????????c?
    =?Class.forName("java.lang.Object");
    ????????????cl?
    =?c.getClassLoader();
    ????????????System.out.println(
    "java.lang.Object's?loader?is?"?+?cl);
    ????????????c?
    =?Class.forName("LoaderSample1");
    ????????????cl?
    =?c.getClassLoader();
    ????????????System.out.println(
    "LoaderSample1's?loader?is?"?+?cl);
    ????????}?
    catch?(Exception?e)?{
    ????????????e.printStackTrace();
    ????????}
    ????}
    }


    在我的機(jī)器上(Sun Java 1.4.2)的運(yùn)行結(jié)果
    sun.misc.Launcher$AppClassLoader@1a0c10f
    sun.misc.Launcher$ExtClassLoader@e2eec8
    null
    java.lang.Object's loader is null
    LoaderSample1's loader is sun.misc.Launcher$AppClassLoader@1a0c10f

    第一行表示,系統(tǒng)類裝載器實(shí)例化自類sun.misc.Launcher$AppClassLoader
    第二行表示,系統(tǒng)類裝載器的parent實(shí)例化自類sun.misc.Launcher$ExtClassLoader
    第三行表示,系統(tǒng)類裝載器parent的parent為bootstrap
    第四行表示,核心類java.lang.Object是由bootstrap裝載的
    第五行表示,用戶類LoaderSample1是由系統(tǒng)類裝載器裝載的
    ?
    ?
    二.parent delegation模型
    從1.2版本開(kāi)始,Java引入了雙親委托模型,從而更好的保證Java平臺(tái)的安全。在此模型下,當(dāng)一個(gè)裝載器被請(qǐng)求裝載某個(gè)類時(shí),它首先委托自己的parent去裝載,若parent能裝載,則返回這個(gè)類所對(duì)應(yīng)的Class對(duì)象,若parent不能裝載,則由parent的請(qǐng)求者去裝載

    圖 1 parent delegation模型
    如圖1所示,loader2的parent為loader1,loader1的parent為system class loader。假設(shè)loader2被要求裝載類MyClass,在parent delegation模型下,loader2首先請(qǐng)求loader1代為裝載,loader1再請(qǐng)求系統(tǒng)類裝載器去裝載MyClass。若系統(tǒng)裝載器能成功裝載,則將MyClass所對(duì)應(yīng)的Class對(duì)象的reference返回給loader1,loader1再將reference返回給loader2,從而成功將類MyClass裝載進(jìn)虛擬機(jī)。若系統(tǒng)類裝載器不能裝載MyClass,loader1會(huì)嘗試裝載MyClass,若loader1也不能成功裝載,loader2會(huì)嘗試裝載。若所有的parent及l(fā)oader2本身都不能裝載,則裝載失敗。
    ?
    若有一個(gè)能成功裝載,實(shí)際裝載的類裝載器被稱為定義類裝載器,所有能成功返回Class對(duì)象的裝載器(包括定義類裝載器)被稱為初始類裝載器。如圖1所示,假設(shè)loader1實(shí)際裝載了MyClass,則loader1為MyClass的定義類裝載器,loader2和loader1為MyClass的初始類裝載器。
    ?
    需要指出的是,Class Loader是對(duì)象,它的父子關(guān)系和類的父子關(guān)系沒(méi)有任何關(guān)系。
    ?
    那么parent delegation模型為什么更安全了?因?yàn)樵诖四P拖掠脩糇远x的類裝載器不可能裝載應(yīng)該由父親裝載器裝載的可靠類,從而防止不可靠甚至惡意的代碼代替由父親裝載器裝載的可靠代碼。實(shí)際上,類裝載器的編寫(xiě)者可以自由選擇不用把請(qǐng)求委托給parent,但正如上所說(shuō),會(huì)帶來(lái)安全的問(wèn)題。
    ?
    ?
    三.命名空間及其作用
    每個(gè)類裝載器有自己的命名空間,命名空間由所有以此裝載器為創(chuàng)始類裝載器的類組成。不同命名空間的兩個(gè)類是不可見(jiàn)的,但只要得到類所對(duì)應(yīng)的Class對(duì)象的reference,還是可以訪問(wèn)另一命名空間的類。
    ?
    例2演示了一個(gè)命名空間的類如何使用另一命名空間的類。在例子中,LoaderSample2由系統(tǒng)類裝載器裝載,LoaderSample3由自定義的裝載器loader負(fù)責(zé)裝載,兩個(gè)類不在同一命名空間,但LoaderSample2得到了LoaderSample3所對(duì)應(yīng)的Class對(duì)象的reference,所以它可以訪問(wèn)LoaderSampl3中公共的成員(如age)。
    例2不同命名空間的類的訪問(wèn)
    /*LoaderSample2.java*/

    import?java.net.*;
    import?java.lang.reflect.*;
    public?class?LoaderSample2?{
    ????
    public?static?void?main(String[]?args)?{
    ????????
    try?{
    ????????????String?path?
    =?System.getProperty("user.dir");
    ????????????URL[]?us?
    =?{new?URL("file://"?+?path?+?"/sub/")};
    ????????????ClassLoader?loader?
    =?new?URLClassLoader(us);
    ????????????Class?c?
    =?loader.loadClass("LoaderSample3");
    ????????????Object?o?
    =?c.newInstance();
    ????????????Field?f?
    =?c.getField("age");
    ????????????
    int?age?=?f.getInt(o);
    ????????????System.out.println(
    "age?is?"?+?age);
    ????????}?
    catch?(Exception?e)?{
    ????????????e.printStackTrace();
    ????????}
    ????}
    }


    /*sub/Loadersample3.java*/

    public?class?LoaderSample3?{
    ????
    static?{
    ????????System.out.println(
    "LoaderSample3?loaded");
    ????}
    ????
    public?int?age?=?30;
    }

    編譯:javac LoaderSample2.java; javac sub/LoaderSample3.java
    運(yùn)行:java LoaderSample2
    LoaderSample3 loaded
    age is 30
    從運(yùn)行結(jié)果中可以看出,在類LoaderSample2中可以創(chuàng)建處于另一命名空間的類LoaderSample3中的對(duì)象并可以訪問(wèn)其公共成員age。
    運(yùn)行時(shí)包(runtime package)
    由同一類裝載器定義裝載的屬于相同包的類組成了運(yùn)行時(shí)包,決定兩個(gè)類是不是屬于同一個(gè)運(yùn)行時(shí)包,不僅要看它們的包名是否相同,還要看的定義類裝載器是否相同。只有屬于同一運(yùn)行時(shí)包的類才能互相訪問(wèn)包可見(jiàn)的類和成員。這樣的限制避免了用戶自己的代碼冒充核心類庫(kù)的類訪問(wèn)核心類庫(kù)包可見(jiàn)成員的情況。假設(shè)用戶自己定義了一個(gè)類java.lang.Yes,并用用戶自定義的類裝載器裝載,由于java.lang.Yes和核心類庫(kù)java.lang.*由不同的裝載器裝載,它們屬于不同的運(yùn)行時(shí)包,所以java.lang.Yes不能訪問(wèn)核心類庫(kù)java.lang中類的包可見(jiàn)的成員。
    ?
    總結(jié)
    命名空間并沒(méi)有完全禁止屬于不同空間的類的互相訪問(wèn),雙親委托模型加強(qiáng)了Java的安全,運(yùn)行時(shí)包增加了對(duì)包可見(jiàn)成員的保護(hù)。
    ?
    二.??? 擴(kuò)展ClassLoader方法
    我們目的是從本地文件系統(tǒng)使用我們實(shí)現(xiàn)的類裝載器裝載一個(gè)類。為了創(chuàng)建自己的類裝載器我們應(yīng)該擴(kuò)展ClassLoader類,這是一個(gè)抽象類。我們創(chuàng)建一個(gè)FileClassLoader extends ClassLoader。我們需要覆蓋ClassLoader中的findClass(String name)方法,這個(gè)方法通過(guò)類的名字而得到一個(gè)Class對(duì)象。

    ????public?Class?findClass(String?name)
    ????{
    ????????
    byte[]?data?=?loadClassData(name);
    ????????
    return?defineClass(name,?data,?0,?data.length);
    ????}


    ???我們還應(yīng)該提供一個(gè)方法loadClassData(String name),通過(guò)類的名稱返回class文件的字
    節(jié)數(shù)組。然后使用ClassLoader提供的defineClass()方法我們就可以返回Class對(duì)象了。

    ????public?byte[]?loadClassData(String?name)
    ????{
    ????????FileInputStream?fis?
    =?null;
    ????????
    byte[]?data?=?null;
    ????????
    try
    ????????{
    ????????????fis?
    =?new?FileInputStream(new?File(drive?+?name?+?fileType));
    ????????????ByteArrayOutputStream?baos?
    =?new?ByteArrayOutputStream();
    ????????????
    int?ch?=?0;
    ????????????
    while?((ch?=?fis.read())?!=?-1)
    ????????????{
    ????????????????baos.write(ch);
    ???????????????
    ????????????}
    ????????????data?
    =?baos.toByteArray();
    ????????}?
    catch?(IOException?e)
    ????????{
    ????????????e.printStackTrace();
    ????????}
    ????????
    ????????
    return?data;
    ????}


    再說(shuō)說(shuō)Package權(quán)限。Java語(yǔ)言規(guī)定,在同一個(gè)包中的class,如果沒(méi)有修飾符,默認(rèn)為Package權(quán)限,包內(nèi)的class都可以訪問(wèn)。但是這還不夠準(zhǔn)確。確切的說(shuō),只有由同一個(gè)ClassLoader裝載的class才具有以上的Package權(quán)限。比如啟動(dòng)類裝載器裝載了java.lang.String,類路徑裝載器裝載了我們自己寫(xiě)的java.lang.Test,它們不能互相訪問(wèn)對(duì)方具有Package權(quán)限的方法。這樣就阻止了惡意代碼訪問(wèn)核心類的Package權(quán)限方法。


    posted on 2009-05-16 23:38 picture talk 閱讀(169) 評(píng)論(0)  編輯  收藏 所屬分類: Java

    主站蜘蛛池模板: 中文字幕亚洲精品资源网| 一级毛片在线免费观看| 亚洲中字慕日产2021| 亚洲人成伊人成综合网久久久 | 国产精品极品美女免费观看| 99在线在线视频免费视频观看| 色视频在线观看免费| 中日韩亚洲人成无码网站| 亚洲第一精品在线视频| 国产AV无码专区亚洲AV漫画| 宅男666在线永久免费观看| 国产a视频精品免费观看| 久久黄色免费网站| 国产A∨免费精品视频| 相泽南亚洲一区二区在线播放| 精品亚洲成A人无码成A在线观看| 亚洲高清在线视频| 亚洲日韩精品射精日| 久久影院亚洲一区| 亚洲精品国产精品国自产观看| 国产午夜免费福利红片| 高清国语自产拍免费视频国产| 无限动漫网在线观看免费 | 亚洲国产中文在线视频| 亚洲三级电影网站| 亚洲成a人片77777老司机| 亚洲人成在线播放网站| 亚洲国产成人高清在线观看| 久久精品国产亚洲一区二区三区| 日韩亚洲国产二区| 色老板亚洲视频免在线观| 亚洲美女激情视频| 亚洲美女视频网站| 666精品国产精品亚洲| 亚洲成av人片在线看片| 亚洲色图校园春色| 亚洲av永久无码精品天堂久久| 亚洲一区欧洲一区| 亚洲av永久无码天堂网| 在线亚洲v日韩v| 成年网站免费入口在线观看|