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

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

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

    Jhonney的專欄

       ----人見人愛
    隨筆 - 49, 文章 - 1, 評論 - 23, 引用 - 0
    數(shù)據(jù)加載中……

    走出ClassLoader迷宮

    quto:http://m.tkk7.com/lihuaxajh/articles/94371.html
    other resources:
        1.http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load.html?page=1
        2.http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load.html?page=2  
        3.http://www.javaworld.com/javaworld/javaqa/2003-03/01-qa-0314-forname.html
        4.http://www.theserverside.com/news/thread.tss?thread_id=40763
        5.http://www.matrix.org.cn/resource/article/43/43875_Class_Loading.html
        6.http://blog.sina.com.cn/s/blog_4b6047bc0100096v.html
        7.http://blog.sina.com.cn/s/blog_4b6047bc0100097p.html
    這個問題經(jīng)常出現(xiàn)在編寫框架代碼
    , 需要動態(tài)加載很多類和資源的時候 . 通常當(dāng)你需要動態(tài)加載資源的時候 , 你至少有三個 ClassLoader 可以選擇 :

    1.   系統(tǒng)類加載器或叫作應(yīng)用類加載器 (system classloader or application classloader)
    2.  當(dāng)前類加載器
    3.  當(dāng)前線程類加載器

    上面的問題指的是最后一種類加載器 . 哪種類加載器是正確的選擇呢 ?

    第一種選擇可以很容易地排除 : 系統(tǒng)類加載器 (system classloader). 這個類加載器處理 -classpath 下的類加載工作 , 可以通過 ClassLoader.getSystemClassLoader() 方法調(diào)用 . ClassLoader 下所有的 getSystemXXX() 的靜態(tài)方法都是通過這個方法定義的 . 在你的代碼中 , 你應(yīng)該盡量少地調(diào)用這個方法 , 以其它的類加載器作為代理 . 否則你的代碼將只能工作在簡單的命令行應(yīng)用中 , 這個時候系統(tǒng)類加載器 (system classloader) JVM 最后創(chuàng)建的類加載器 . 一但你把代碼移到 EJB, Web 應(yīng)用或 Java Web Start 應(yīng)用中 , 一定會出問題 .

          所以我們來看第二種選擇 : 當(dāng)前上下文環(huán)境下的類加載器 . 根據(jù)定義 , 當(dāng)前類加載器就是你當(dāng)前方法所屬的類的加載器 . 在運(yùn)行時類之間動態(tài)聯(lián)編 , 及調(diào)用 Class.forName,() Class.getResource() 等類似方法時 , 這個類加載器會被隱含地使用 . It is also used by syntactic constructs like X.class class literals.

        線程上下文類型加載器是在Java 2平臺上被引入的. 每一個線程都有一個類加載器與之對應(yīng)(除非這個線程是被本地代碼創(chuàng)建的). 這個類加載器是通過Thread.setContextClassLoaser()方法設(shè)置的. 如果你不在線程構(gòu)造后調(diào)用這個方法, 這個線程將從它的父線程中繼承相應(yīng)的上下文類加載器. 如果在整個應(yīng)用中你不做任何特殊設(shè)置, 所有的線程將都以系統(tǒng)類加載器(system classloader)作為自己的線程上下文類加載器. 自從WebJ2EE應(yīng)用服務(wù)器使用成熟的類加載器機(jī)制來實現(xiàn)諸如JNDI, 線程池, 組件熱部署等功能以來, 這種在整個應(yīng)用中不做任何線程類加載器設(shè)置的情況就很少了.

        為什么線程上下文類加載器存在于如此重要的位置呢? 這個概念在J2SE中的引入并不引人注目. 很多開發(fā)人員對這一概念迷惑的原因是Sun公司在這方面缺乏適當(dāng)?shù)闹敢臀臋n.

        事實上, 上下文類加載器提供了類加載機(jī)制的后門, 這一點也在J2SE中被引入了. 通常, JVM中的所有類加載器被組織成了有繼承層次的結(jié)構(gòu), 每一個類加載器(除了引導(dǎo)JVM的原始類加載器)都有一個父加載器. 每當(dāng)被請示加載類時, 類加載器都會首先請求其父類加載器, 只有當(dāng)父類加載器不能加載時, 才會自己進(jìn)行類加載.

       有時候這種類加載的順序安排不能正常工作, (此 處的意思是:正常情況下都是從子類加載器到根類加載器請求,萬一有根類里需要加載子類時,這種順序就不能滿足要求,就要有一條反向的通道,即得到子類加載 器,這樣就用到了thread context classloader,因為通過thread.getcontextclassloader()可以得到子類加載器).通常當(dāng)必須動態(tài)加載應(yīng)用程序開發(fā)人員提供的資源的時候. JNDI為例: 它的內(nèi)容(J2SE1.3開始)就在rt.jar中的引導(dǎo)類中實現(xiàn)了, 但是這些JNDI核心類需要動態(tài)加載由獨立廠商實現(xiàn)并部署在應(yīng)用程序的classpath下的JNDI提供者. 這種情況就要求一個父classloader(本例, 就是引導(dǎo)類加載器)去加載對于它其中一個子classloader(本例, 系統(tǒng)類加載器)可見的類. 這時通常的類加載代理機(jī)制不能實現(xiàn)這個要求. 解決的辦法(workaround)就是, JNDI核心類使用當(dāng)前線程上下文的類加載器, 這樣, 就基本的類加載代理機(jī)制的相反方向建立了一條有效的途徑.

        另外, 上面一段可能讓你想起一些其它的事情: XML解析Java API(JAXP). 是的, 當(dāng)JAXP只是J2SE的擴(kuò)展進(jìn), 它很自然地用當(dāng)前類加載器來引導(dǎo)解析器的實現(xiàn). 而當(dāng)JAXP被加入到J2SE1.4的核心類庫中時, 它的類加載也就改成了用當(dāng)前線程類加載器, JNDI的情況完全類似(也使很多程序員很迷惑). 明白為什么我說來自Sun的指導(dǎo)很缺乏了吧?

       在以上的介紹之后, 我們來看關(guān)鍵問題: 這兩種選擇(當(dāng)前類加載器和當(dāng)前線程類加載器)都不是在所有環(huán)境下都適用. 有些人認(rèn)為當(dāng)前線程類加載器應(yīng)該成為新的標(biāo)準(zhǔn)策略. 但是, 如果這樣, 當(dāng)多個線程通過共享數(shù)據(jù)進(jìn)行交互的時, 將會呈現(xiàn)出一幅極其復(fù)雜的類加載的畫面, 除非它們?nèi)渴褂昧送粋€上下文的類加載器. 進(jìn)一步說, 在某些遺留下來的解決方案中, 委派到當(dāng)前類加載器的方法已經(jīng)是標(biāo)準(zhǔn). 比如對Class.forName(String)的直接調(diào)用(這也是我為什么推薦盡量避免對這個方法進(jìn)行調(diào)用的原因). 即使你努力去只調(diào)用上下文相關(guān)的類加載器, 仍然會有一些代碼會不由你控制. 這種不受控制的類加載委派機(jī)制是混入是很危險的.

        更嚴(yán)重的問題, 某些應(yīng)用服務(wù)器把環(huán)境上下文及當(dāng)前類加載器設(shè)置到不同的類加載器實例上, 而這些類加載器有相同的類路徑但卻沒有委派機(jī)制中的父子關(guān)系. 想想這為什么十分可怕. 要知道類加載器定義并加載的類實例會帶有一個JVM內(nèi)部的ID. 如果當(dāng)前類加載器加載一個類X的實例, 這個實例調(diào)用JNDI查找類Y的實例, 些時的上下文的類加載器也可以定義了加載類Y實例. 這個類Y的定義就與當(dāng)前類加載器看到的類Y的定義不同. 如果進(jìn)行強(qiáng)制類型轉(zhuǎn)換, 則產(chǎn)生異常.

       這種混亂的情況還將在Java中存在一段時間. 對于那些需要動態(tài)加載資源的J2SEAPI, 我們來猜想它們的類加策略. 例如:

    Ø         JNDI 使用線程上下文類加載器

    Ø         Class.getResource() Class.forName()使用當(dāng)前類加載器

    Ø         JAXP(J2SE 1.4 及之后)使用線程上下文類加載器

    Ø         java.util.ResourceBundle 使用調(diào)用者的當(dāng)前類加載器

    Ø         URL protocol handlers specified via java.protocol.handler.pkgs system property are looked up in the bootstrap and system classloaders only

    Ø         Java 序列化API默認(rèn)使用調(diào)用者當(dāng)前的類加載器

    這些類及資源的加載策略問題, 肯定是J2SE領(lǐng)域中文檔最及說明最缺乏的部分了.

    posted on 2008-03-23 02:57 Jhonney 閱讀(463) 評論(0)  編輯  收藏


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


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 亚洲永久在线观看| 啊v在线免费观看| 婷婷亚洲综合五月天小说| 无遮挡国产高潮视频免费观看| 无码国模国产在线观看免费| 亚洲精品无码av片| 国产一级淫片视频免费看| 色噜噜狠狠色综合免费视频| 亚洲国产精品毛片av不卡在线| 黄网站在线播放视频免费观看| 亚洲精品国产精品乱码不卞| 美女巨胸喷奶水视频www免费| 久久久无码精品亚洲日韩软件 | selaoban在线视频免费精品| 免费在线观看黄网站| 好吊色永久免费视频大全| 亚洲理论电影在线观看| 毛片无码免费无码播放 | 久久精品国产亚洲av麻豆小说 | 国产亚洲男人的天堂在线观看 | jlzzjlzz亚洲乱熟在线播放| 国产综合免费精品久久久| 亚洲成人中文字幕| 国产大片线上免费观看| 亚洲暴爽av人人爽日日碰| 亚洲综合亚洲综合网成人| 亚洲免费在线视频| 亚洲乱码在线观看| 亚洲午夜激情视频| **实干一级毛片aa免费| 亚洲AV无码专区在线观看成人| 亚洲国产婷婷香蕉久久久久久| 玖玖在线免费视频| 亚洲国产精品日韩av不卡在线| 亚洲伊人久久综合中文成人网 | 国产伦一区二区三区免费| 国产黄在线播放免费观看| 亚洲欧洲日韩综合| 久久亚洲欧洲国产综合| 中文字幕无码免费久久99| www永久免费视频|