1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        最新版JDK15的JVM類加載器詳解

        共 3827字,需瀏覽 8分鐘

         ·

        2021-01-20 22:16


        ? 點(diǎn)擊上方“JavaEdge”,關(guān)注公眾號

        設(shè)為“星標(biāo)”,好文章不錯過!


        1 類加載器


        在類加載器家族中存在著類似人類社會的權(quán)力等級制度:



        1.1?Bootstrap


        由C/C++實(shí)現(xiàn),啟動類加載器,屬最高層,JVM啟動時創(chuàng)建,通常由與os相關(guān)的本地代碼實(shí)現(xiàn),是最根基的類加載器。

        JDK8 時


        需要注意的是,Bootstrap ClassLoader智慧加載特定名稱的類庫,比如rt.jar.這意味我們自定義的jar扔到\jre\lib也不會被加載.

        負(fù)責(zé)將/jre/lib- Xbootclasspath參數(shù)指定的路徑中的,且是虛擬機(jī)識別的類庫加載到內(nèi)存中(按照名字識別,比如rt.jar,對于不能識別的文件不予裝載),比如:

        • Object

        • System

        • String

        • Java運(yùn)行時的rt.jar等jar包

        • 系統(tǒng)屬性sun.boot.class.path指定的目錄中特定名稱的jar包

        在JVM啟動時,通過Bootstrap ClassLoader加載rt.jar,并初始化sun.misc.Launcher從而創(chuàng)建Extension ClassLoaderApplication ClassLoader的實(shí)例。
        查看Bootstrap ClassLoader到底初始化了那些類庫:

        URL[] urLs = Launcher.getBootstrapClassPath().getURLs();       for (URL urL : urLs) {           System.out.println(urL.toExternalForm());       }

        JDK9 后


        負(fù)責(zé)加載啟動時的基礎(chǔ)模塊類,比如:

        • java.base

        • java.management

        • java.xml




        1.2?Platform ClassLoader


        JDK8 時Extension ClassLoader


        只有一個實(shí)例,由sun.misc.Launcher$ExtClassLoader實(shí)現(xiàn):

        • 負(fù)責(zé)加載\lib\extjava.ext.dirs系統(tǒng)變量指定的路徑中的所有類庫

        • 加載一些擴(kuò)展的系統(tǒng)類,比如XML、加密、壓縮相關(guān)的功能類等


        JDK9時替換為平臺類加載器


        加載一些平臺相關(guān)的模塊,比如java.scripting、java.compiler*、?java.corba*

        那為何 9 時廢除替換了呢?

        JDK8 的主要加載 jre lib 的ext,擴(kuò)展 jar 包時使用,這樣操作并不推薦,所以廢除。而 JDK9 有了模塊化,更無需這種擴(kuò)展加載器。



        1.3?Application ClassLoader


        只有一個實(shí)例,由sun.misc.Launcher$AppClassLoader實(shí)現(xiàn)。

        JDK8 時


        負(fù)責(zé)加載系統(tǒng)環(huán)境變量ClassPath或者系統(tǒng)屬性java.class.path指定目錄下的所有類庫。
        如果應(yīng)用程序中沒有定義自己的加載器,則該加載器也就是默認(rèn)的類加載器。該加載器可以通過java.lang.ClassLoader.getSystemClassLoader獲取。

        JDK9 后


        應(yīng)用程序類加載器,用于加載應(yīng)用級別的模塊,比如:

        • jdk.compiler

        • jdk.jartool

        • jdk.jshell

        • classpath路徑中的所有類庫

        第二、三層類加載器為Java語言實(shí)現(xiàn),用戶也可以



        1.4 自定義類加載器

        用戶自定義的加載器,是java.lang.ClassLoader的子類,用戶可以定制類的加載方式;只不過自定義類加載器其加載的順序是在所有系統(tǒng)類加載器的最后。



        1.5 Thread Context ClassLoader


        每個線程都有一個類加載器(jdk 1.2后引入),稱之為Thread Context ClassLoader,如果線程創(chuàng)建時沒有設(shè)置,則默認(rèn)從父線程中繼承一個,如果在應(yīng)用全局內(nèi)都沒有設(shè)置,則所有Thread Context ClassLoader為Application ClassLoader.可通過Thread.currentThread().setContextClassLoader(ClassLoader)來設(shè)置,通過Thread.currentThread().getContextClassLoader()來獲取.

        線程上下文加載器有什么用?


        該類加載器容許父類加載器通過子類加載器加載所需要的類庫,也就是打破了我們下文所說的雙親委派模型。
        這有什么好處呢?
        利用線程上下文加載器,我們能夠?qū)崿F(xiàn)所有的代碼熱替換,熱部署,Android中的熱更新原理也是借鑒如此。

        2 驗(yàn)證類加載器




        2.1 查看本地類加載器



        在JDK8環(huán)境中,執(zhí)行結(jié)果如下

        AppClassLoader的Parent為Bootstrap,它是通過C/C++實(shí)現(xiàn)的,并不存在于JVM體系內(nèi),所以輸出為 null。



        類加載器的特點(diǎn)


        • 類加載器并不需要等到某個類"首次主動使用”的時候才加載它,JVM規(guī)范允許類加載器在預(yù)料到某個類將要被使用的時候就預(yù)先加載它

        • Java程序不能直接引用啟動類加載器,直接設(shè)置classLoader為null,默認(rèn)就使用啟動類加載器

        • 如果在加載的時候.class文件缺失,會在該類首次主動使用時通知LinkageError錯誤,如果一直沒有被使用,就不會報錯

        • 如果沒有指定父加載器,默認(rèn)就是啟動加載器

        • 每個類加載器都有自己的命名空間,命名空間由該加載器及其所有父加載器所加載的類構(gòu)成。不同的命名空間,可以出現(xiàn)類的全路徑名相同的情況

        • 運(yùn)行時包由同一個類加載器的類構(gòu)成,決定兩個類是否屬于同一個運(yùn)行時包,不僅要看全路徑名是否一樣,還要看定義類加載器是否相同。只有屬于同一個運(yùn)行時包的類才能實(shí)現(xiàn)相互包內(nèi)可見

        低層次的當(dāng)前類加載器,不能覆蓋更高層次類加載器已經(jīng)加載的類
        如果低層次的類加載器想加載一個未知類,要非常禮貌地向上逐級詢問:“請問,這個類已經(jīng)加載了嗎?”
        被詢問的高層次類加載器會自問兩個問題

        • 我是否已加載過此類

        • 如果沒有,是否可以加載此類

        只有當(dāng)所有高層次類加載器在兩個問題的答案均為“否”時,才可以讓當(dāng)前類加載器加載這個未知類
        左側(cè)綠色箭頭向上逐級詢問是否已加載此類,直至
        Bootstrap ClassLoader,然后向下逐級嘗試是否能夠加載此類,如果都加載不了,則通知發(fā)起加載請求的當(dāng)前類加載器,準(zhǔn)予加載
        在右側(cè)的三個小標(biāo)簽里,列舉了此層類加載器主要加載的代表性類庫,事實(shí)上不止于此

        通過如下代碼可以查看Bootstrap 所有已加載類庫

        執(zhí)行結(jié)果

        Bootstrap加載的路徑可以追加,不建議修改或刪除原有加載路徑
        在JVM中增加如下啟動參數(shù),則能通過
        Class.forName正常讀取到指定類,說明此參數(shù)可以增加Bootstrap的類加載路徑:

        -Xbootclasspath/a:/Users/sss/book/ easyCoding/byJdk11/src

        如果想在啟動時觀察加載了哪個jar包中的哪個類,可以增加

        -XX:+TraceClassLoading

        此參數(shù)在解決類沖突時非常實(shí)用,畢竟不同的JVM環(huán)境對于加載類的順序并非是一致的
        有時想觀察特定類的加載上下文,由于加載的類數(shù)量眾多,調(diào)試時很難捕捉到指定類的加載過程,這時可以使用條件斷點(diǎn)功能
        比如,想查看HashMap的加載過程,在loadClass處打個斷點(diǎn),并且在condition框內(nèi)輸入如圖

        JVM如何確立每個類在JVM的唯一性


        類的全限定名和加載這個類的類加載器的ID

        在學(xué)習(xí)了類加載器的實(shí)現(xiàn)機(jī)制后,知道雙親委派模型并非強(qiáng)制模型,用戶可以自定義類加載器,在什么情況下需要自定義類加載器呢?

        • 隔離加載類
          在某些框架內(nèi)進(jìn)行中間件與應(yīng)用的模塊隔離,把類加載到不同的環(huán)境
          比如,阿里內(nèi)某容器框架通過自定義類加載器確保應(yīng)用中依賴的jar包不會影響到中間件運(yùn)行時使用的jar包

        • 修改類加載方式

          類的加載模型并非強(qiáng)制,除Bootstrap外,其他的加載并非一定要引入,或者根據(jù)實(shí)際情況在某個時間點(diǎn)進(jìn)行按需進(jìn)行動態(tài)加載

        • 擴(kuò)展加載源

          比如從數(shù)據(jù)庫、網(wǎng)絡(luò),甚至是電視機(jī)機(jī)頂盒進(jìn)行加載

        • 防止源碼泄露

          Java代碼容易被編譯和篡改,可以進(jìn)行編譯加密。那么類加載器也需要自定義,還原加密的字節(jié)碼。


        實(shí)現(xiàn)自定義類加載器的步驟

        • 繼承ClassLoader

        • 重寫findClass()方法

        • 調(diào)用defineClass()方法

        一個簡單的類加載器實(shí)現(xiàn)的示例代碼如下

        由于中間件一般都有自己的依賴jar包,在同一個工程內(nèi)引用多個框架時,往往被迫進(jìn)行類的仲裁。按某種規(guī)則jar包的版本被統(tǒng)一指定, 導(dǎo)致某些類存在包路徑、類名相同的情況,就會引起類沖突,導(dǎo)致應(yīng)用程序出現(xiàn)異常。
        主流的容器類框架都會自定義類加載器,實(shí)現(xiàn)不同中間件之間的類隔離,有效避免了類沖突。


        往期推薦



        由于不知線程池的bug,某Java程序員叕被祭天

        程序員因重復(fù)記錄日志撐爆ELK被辭退!

        擁抱Kubernetes,再見了Spring Cloud

        云原生時代下的網(wǎng)關(guān)V.S反向代理




        目前交流群已有?800+人,旨在促進(jìn)技術(shù)交流,可關(guān)注公眾號添加筆者微信邀請進(jìn)群


        喜歡文章,點(diǎn)個“在看、點(diǎn)贊、分享”素質(zhì)三連支持一下~

        瀏覽 74
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            亚洲欧美第一在线 | 国产精品在线看 | 亚洲天堂一区二区三区 | 9l蝌蚪PORNY中文 | 在线播放欧美性爱 | 欧美操逼虐待视频网 | 国产伦久久久精品A88 | 亚洲伦理久久 | 超碰成人国产一区二区三区 | 97大香蕉在线视频 |