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

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

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

    隨筆 - 45, 文章 - 6, 評論 - 4, 引用 - 0
    數(shù)據(jù)加載中……

    Classloader的基本概念

            Classloader在運行期會以父/子的層次結(jié)構(gòu)存在,每個Classloader的實例都持有其父Classloader的引用,而父Classloader并不持有子Classloader的引用,從而形成一條單向鏈,當一個類裝載請求被提交到某個Classloader時,其默認的類裝載過程如下:
  • 檢查這個類有沒有被裝載過,如果已經(jīng)裝載過,則直接返回;

  • 調(diào)用父Classloader去裝載類,如果裝載成功直接返回;

  • 調(diào)用自身的裝載類的方法,如果裝載成功直接返回;

  • 上述所有步驟都沒有成功裝載到類,拋出ClassNotFoundException;

  •         每一層次的Classloader都重復上述動作。

            簡單說,當Classloader鏈上的某一Classloader收到類裝載請求時,會按順序向上詢問其所有父節(jié)點,直至最頂端(BootstrapClassLoader),任何一個節(jié)點成功受理了此請求,則返回,如果所有父節(jié)點都不能受理,這時候才由被請求的Classloader自身來裝載這個類,如果仍然不能裝載,則拋出異常。

    類裝載的方式

            類裝載的方式主要有兩種:顯式的和隱式的。

            顯式類裝載

            發(fā)生在使用以下方法調(diào)用進行裝載類的時候:

            ClassLoader.loadClass()(使用指定的Classloader進行裝載)

            Class.forName()(使用當前類的Caller Classloader進行裝載)

            當調(diào)用上述方法的時候,指定的Class(以類名為參數(shù))由Classloader裝入。這兩個方法的行為有輕微的區(qū)別,Class.forName()在類裝載完成后,會對類進行初始化,而ClassLoader.loadClass()只負責裝載類

            隱式類裝載

            發(fā)生在由于引用、實例化或繼承導致需要裝載類的時候。隱式類裝載是在幕后啟動的,JVM會解析必要的引用并裝載類。

            類的裝載通常組合了顯式和隱式兩種方式。例如,Classloader可能先顯式地裝載一個類,然后再隱式地裝載它引用的其它類。

    一個基本的Classloader的層次結(jié)構(gòu)
            
                                                                

            上圖顯示了一個基本的Classloader的層次結(jié)構(gòu)。在給定層次上的Classloader不能引用任何層次低于它的Classloader,另外,它的子Classloader裝載的類對于其是不可見的。在上圖中,如果Foo.class是由ClassLoaderB裝載的,并且Foo.class依賴于Bar.class,那么Bar.class必須由ClassLoaderA或B裝載。如果Bar.class只是對ClassLoaderC和D可見,那么將會發(fā)生ClassNotFoundException或者NoClassDefFoundError異常。

    如果Bar.class分別對于兩個平級的Classloader可見(例如C和D),但對于它們的父Classloader不可見,那么當類裝載請求發(fā)送到這兩個Classloader時,每一個Classloader會裝載自己版本的類。ClassLoaderC裝載的Bar.class的實例將不兼容于ClassLoaderD裝載的Bar.class的實例。如果對Classloader的層次結(jié)構(gòu)不了解,試圖使用由ClassLoaderC裝載的類去造型一個ClassLoaderD裝載的Bar.class的實例,則會發(fā)生造型失敗(ClassCastException)。

    基本的Classloader
            最基本的Classloader是Bootstrap Classloader和System Classloader(也有人稱之為AppClassLoader),只要寫過java程序,都會用到這兩個Classloader。

    • Bootstrap Classloader

      這個Classloader裝載Java虛擬機提供的基本運行時刻類($JAVA_HOME/jre/lib),還包括放置在系統(tǒng)擴展目錄($JAVA_HOME/jre/lib/ext)內(nèi)的JAR文件中的類。這個Classloader是java程序最頂層的Classloader,只有它沒有父Classloader。如果你將一個自己寫的類或第三方j(luò)ar包放進$JAVA_HOME/jre/lib/ext目錄中,那么它將被Bootstrap Classloader裝載。

    • System Classloader

      System Classloader通常負責裝載系統(tǒng)環(huán)境變量CLASSPATH中設(shè)置的類。由System Classloader裝載的類對于Apusic服務(wù)器內(nèi)部的類和部署在Apusic服務(wù)器上的J2EE應(yīng)用(通常打包成ear)都是可見的。%APUSIC_HOME%/lib目錄下的jar文件是Apusic應(yīng)用服務(wù)器的核心類,一般把這些jar文件都加在系統(tǒng)CLASSPATH中。另外,一些公用類也可以加在系統(tǒng)CLASSPATH中,如JDBC驅(qū)動程序等。


    自定義Classloader
            在編寫應(yīng)用代碼的時候,常常有需要動態(tài)加載類和資源,比如顯式的調(diào)用classLoader.loadClass(“ClassName”),雖然直接使用ClassLoader.getSystemClassLoader(),可以得到SystemlassLoader來完成這項任務(wù)。但是,由于System Classloader是JVM創(chuàng)建的Classloader,它的職責有限,只適合于普通的java應(yīng)用程序,在很多復雜場景中不能滿足需求,比如在應(yīng)用服務(wù)器中。這時候就需要自行實現(xiàn)一個Classloader的子類,實現(xiàn)特定的行為。Apusic應(yīng)用服務(wù)器中就定義了若干個特有的Classloader,負責裝載部署在Apusic中的JavaEE應(yīng)用中的類,這里并不試圖去描述如何實現(xiàn)一個自定義的Classloader.

    Caller Classloader和線程上下文Classloader
            動態(tài)加載資源時,往往有三種Classloader可選擇:System ClassloaderCaller Classloader當前線程的上下文Classloader。System Classloader前面已經(jīng)描述過了,下面我們看看什么是Caller Classloader、當前線程的上下文Classloader。
            

            Caller Classloader

            Caller Classloader指的是當前所在的類裝載時使用的Classloader,它可能是System Classloader,也可能是一個自定義的Classloader,這里,我們都稱之為Caller Classloader。我們可以通過getClass().getClassLoader()來得到Caller Classloader。例如,存在A類,是被AClassLoader所加載,A.class.getClassLoader()為AClassLoader的實例,它就是A.class的Caller Classloader。

            如果在A類中使用new關(guān)鍵字,或者Class.forName(String className)和Class.getResource(String resourceName)方法,那么這時也是使用Caller Classloader來裝載類和資源。比如在A類中初始化B類:

    /**
      * A.java
    */
    ...
    public void foo() {
        B b = new B();
        b.setName("b");
    }
            那么,B類由當前Classloader,也就是AClassloader裝載。同樣的,修改上述的foo方法,其實現(xiàn)改為:

            Class clazz = Class.forName("foo.B");

    最終獲取到的clazz,也是由AClassLoader所裝載。

            那么,如何使用指定的Classloader去完成類和資源的裝載呢?或者說,當需要去實例化一個Caller Classloader和它的父Classloader都不能裝載的類時,怎么辦呢?

            一個很典型的例子是JAXP,當使用xerces的SAX實現(xiàn)時,我們首先需要通過rt.jar中的javax.xml.parsers.SAXParserFactory.getInstance()得到xercesImpl.jar中的org.apache.xerces.jaxp.SAXParserFactoryImpl的實例。由于JAXP的框架接口的class位于JAVA_HOME/lib/rt.jar中,由Bootstrap Classloader裝載,處于Classloader層次結(jié)構(gòu)中的最頂層,而xercesImpl.jar由低層的Classloader裝載,也就是說SAXParserFactoryImpl是在SAXParserFactory中實例化的,如前所述,使用SAXParserFactory的Caller Classloader(這里是Bootstrap Classloader)是完成不了這個任務(wù)的。

    這時,我們就需要了解一下線程上下文Classloader了

            線程上下文Classloader

    每個線程都有一個關(guān)聯(lián)的上下文Classloader。如果使用new Thread()方式生成新的線程,新線程將繼承其父線程的上下文Classloader。如果程序?qū)€程上下文Classloader沒有任何改動的話,程序中所有的線程將都使用System Classloader作為上下文Classloader。

    當使用Thread.currentThread().setContextClassLoader(classloader)時,線程上下文Classloader就變成了指定的Classloader了。此時,在本線程的任意一處地方,調(diào)用Thread.currentThread().getContextClassLoader(),都可以得到前面設(shè)置的Classloader。

    回到JAXP的例子,假設(shè)xercesImpl.jar只有AClassLoader能裝載,現(xiàn)在A.class內(nèi)部要使用JAXP,但是A.class卻不是由AClassLoader或者它的子Classloader裝載的,那么在A.class中,應(yīng)該這樣寫才能正確得到xercesImpl的實現(xiàn):

    AClassLoader aClassLoader = new AClassLoader(parent);
    Thread.currentThread().setContextClassLoader(aClassLoader);
    SAXParserFactory factory = SAXParserFactory.getInstance();
    ...
            JAXP這時就可以通過線程上下文Classloader裝載xercesImpl的實現(xiàn)類了,當然,還有一個前提是在配制文件或啟動參數(shù)中指定了使用xerces作為JAXP的實現(xiàn)。下面是JAXP中的代碼片斷:
    ClassLoader cl = Thread.currentThread().getContextClassLoader();

    Class providerClass = cl.loadClass(className);

    JVM中類的唯一性
            JVM為每一個Classloader維護一個唯一標識。在一個JVM里(對應(yīng)一個Java進程),可以由不同的Classloader裝載多個同名的類(指包名和類名都完全相同,下同),為了唯一地標識被不同Classloader裝載的類,JVM會在被裝載的類名前加上裝載該類的Classloader的標識。

    posted on 2009-10-31 23:20 liyang 閱讀(367) 評論(0)  編輯  收藏 所屬分類: j2se


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


    網(wǎng)站導航:
     
    主站蜘蛛池模板: 亚洲精品无码少妇30P| 久久亚洲精品无码VA大香大香| 91嫩草亚洲精品| 久久久久久成人毛片免费看| 亚洲自偷自偷偷色无码中文| 国产免费一区二区三区免费视频| 免费大黄网站在线看| 最新亚洲人成无码网站| 国产一级淫片a免费播放口之| 亚洲国产成人久久精品软件| 日本免费v片一二三区| 久久亚洲精品成人无码| 国产免费私拍一区二区三区 | 亚洲av无码专区国产乱码在线观看| 国产99精品一区二区三区免费 | 国产成人AV片无码免费| 亚洲AV成人精品网站在线播放| 免费视频一区二区| 亚洲欧洲中文日产| 18禁成年无码免费网站无遮挡 | 亚洲一区AV无码少妇电影| 国产老女人精品免费视频| 国产AV日韩A∨亚洲AV电影| 爱情岛论坛网亚洲品质自拍| a级毛片高清免费视频就| 亚洲精品综合久久中文字幕| 成人性生交大片免费看午夜a| 另类图片亚洲校园小说区| 亚洲精品乱码久久久久久自慰| 亚洲人成免费电影| 国产偷国产偷亚洲清高APP| 亚洲男人的天堂在线va拉文| 一级毛片免费视频| 亚洲日韩国产二区无码| 国产精品亚洲不卡一区二区三区| 在线观看片免费人成视频无码| 亚洲精品日韩专区silk| 国产精品免费电影| 日本免费人成网ww555在线| 在线综合亚洲欧洲综合网站| 久久精品国产亚洲7777|