Java類(lèi)加載源碼閱讀

JVM自帶加載器

  • 啟動(dòng)類(lèi)加載器 BootStrap ClassLoader:最頂層的類(lèi)加載器,負(fù)責(zé)加載 JAVA_HOME\lib 目錄中的稻爬,或通過(guò)-Xbootclasspath參數(shù)指定路徑中的蒿秦,且被虛擬機(jī)認(rèn)可(按文件名識(shí)別座享,如rt.jar)的類(lèi)菱涤〕裾ぃ可以通System.getProperty("sun.boot.class.path")查看加載的路徑海诲。
  • 擴(kuò)展類(lèi)加載器 Extention ClassLoader:主要加載目錄%JRE_HOME%\lib\ext目錄下的jar包和class文件繁莹,或通過(guò)java.ext.dirs系統(tǒng)變量指定路徑中的類(lèi)庫(kù)。也可以通過(guò)System.out.println(System.getProperty("java.ext.dirs"))查看加載類(lèi)文件的路徑特幔。
  • 應(yīng)用程序類(lèi)加載器 Application ClassLoader:也叫做系統(tǒng)類(lèi)加載器咨演,可以通過(guò)getSystemClassLoader()獲取,負(fù)責(zé)加載用戶(hù)路徑classpath上的類(lèi)庫(kù)蚯斯。如果沒(méi)有自定義類(lèi)加載器薄风,一般這個(gè)就是默認(rèn)的類(lèi)加載器饵较。


類(lèi)加載層次關(guān)系

類(lèi)加載層次關(guān)系

類(lèi)加載器之間的這種層次關(guān)系叫做雙親委派模型。

雙親委派模型要求除了頂層的啟動(dòng)類(lèi)加載器(Bootstrap ClassLoader)外遭赂,其余的類(lèi)加載器都應(yīng)當(dāng)有自己的父類(lèi)加載器循诉。這里的類(lèi)加載器之間的父子關(guān)系一般不是以繼承關(guān)系實(shí)現(xiàn)的,而是用組合實(shí)現(xiàn)的撇他。

  • 下面看一段源碼
public class Launcher {
    private static Launcher launcher = new Launcher();
    private static String bootClassPath =
        System.getProperty("sun.boot.class.path");

    public static Launcher getLauncher() {
        return launcher;
    }

    private ClassLoader loader;

    public Launcher() {
        // Create the extension class loader
        ClassLoader extcl;
        try {
            extcl = ExtClassLoader.getExtClassLoader();
        } catch (IOException e) {
            throw new InternalError(
                "Could not create extension class loader", e);
        }

        // Now create the class loader to use to launch the application
        try {
            loader = AppClassLoader.getAppClassLoader(extcl);
        } catch (IOException e) {
            throw new InternalError(
                "Could not create application class loader", e);
        }

        Thread.currentThread().setContextClassLoader(loader);
    }

    /*
     * Returns the class loader used to launch the main application.
     */
    public ClassLoader getClassLoader() {
        return loader;
    }
    /*
     * The class loader used for loading installed extensions.
     */
    static class ExtClassLoader extends URLClassLoader {}

    /**
      * The class loader used for loading from java.class.path.
      * runs in a restricted security context.
      */
    static class AppClassLoader extends URLClassLoader {}


從源碼中我們看到
(1)Launcher初始化的時(shí)候創(chuàng)建了ExtClassLoader以及AppClassLoader茄猫,并將ExtClassLoader實(shí)例傳入到AppClassLoader中。
(2)雖然上一段源碼中沒(méi)見(jiàn)到創(chuàng)建BoopStrap ClassLoader困肩,但是程序一開(kāi)始就執(zhí)行了System.getProperty("sun.boot.class.path")划纽。

附上Launcher相關(guān)文章:
https://blog.csdn.net/jyxmust/article/details/72357372?utm_source=itdadao&utm_medium=referral

  • 類(lèi)加載器中的繼承關(guān)系
    AppClassLoader的父加載器為ExtClassLoaderExtClassLoader的父加載器為null锌畸,BoopStrap ClassLoader為頂級(jí)加載器勇劣。

類(lèi)加載機(jī)制-雙親委托

當(dāng)JVM加載Test.class類(lèi)的時(shí)候

  • 首先會(huì)到自定義加載器中查找,看是否已經(jīng)加載過(guò)蹋绽,如果已經(jīng)加載過(guò)芭毙,則返回該類(lèi)。
  • 如果自定義加載器沒(méi)有加載過(guò)卸耘,則詢(xún)問(wèn)上一層加載器(即AppClassLoader)是否已經(jīng)加載過(guò)Test.class退敦。
  • 如果沒(méi)有加載過(guò),則詢(xún)問(wèn)上一層加載器(ExtClassLoader)是否已經(jīng)加載過(guò)蚣抗。
  • 如果沒(méi)有加載過(guò)侈百,則繼續(xù)詢(xún)問(wèn)上一層加載(BoopStrap ClassLoader)是否已經(jīng)加載過(guò)。
  • 如果BoopStrap ClassLoader沒(méi)有加載過(guò)翰铡,則到自己指定類(lèi)加載路徑sun.boot.class.path下查看是否有Test.class字節(jié)碼钝域,有則加載并返回加載后的類(lèi)c = findBootstrapClassOrNull(name)
  • 如果還是沒(méi)找到調(diào)用c = findClass(name)到加載器ExtClassLoader指定的類(lèi)加載路徑java.ext.dirs下查找class文件锭魔,有則加載并返回類(lèi)例证。
  • 依此類(lèi)推,最后到自定義類(lèi)加載器指定的路徑還沒(méi)有找到Test.class字節(jié)碼迷捧,則拋出異常ClassNotFoundException织咧。


這里注意
每個(gè)自定義的類(lèi)加載器都需要重寫(xiě)findClass方法,該方法的作用是到指定位置查找class文件并加載到JVM中漠秋,如果找不到則拋出ClassNotFoundException異常笙蒙。


類(lèi)加載機(jī)制-雙親委托


雙親委派模型最大的好處就是讓Java類(lèi)同其類(lèi)加載器一起具備了一種帶優(yōu)先級(jí)的層次關(guān)系。這句話(huà)可能不好理解庆锦,我們舉個(gè)例子捅位。比如我們要加載頂層的Java類(lèi)——java.lang.Object類(lèi),無(wú)論我們用哪個(gè)類(lèi)加載器去加載Object類(lèi),這個(gè)加載請(qǐng)求最終都會(huì)委托給Bootstrap ClassLoader艇搀,這樣就保證了所有加載器加載的Object類(lèi)都是同一個(gè)類(lèi)尿扯。


雙親委派模型的實(shí)現(xiàn)比較簡(jiǎn)單,在java.lang.ClassLoaderloadClass方法中:

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                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.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }
/**
     * Finds the class with the specified <a href="#name">binary name</a>.
     * This method should be overridden by class loader implementations that
     * follow the delegation model for loading classes, and will be invoked by
     * the {@link #loadClass <tt>loadClass</tt>} method after checking the
     * parent class loader for the requested class.  The default implementation
     * throws a <tt>ClassNotFoundException</tt>.
     *
     * @param  name
     *         The <a href="#name">binary name</a> of the class
     *
     * @return  The resulting <tt>Class</tt> object
     *
     * @throws  ClassNotFoundException
     *          If the class could not be found
     *
     * @since  1.2
     */
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        throw new ClassNotFoundException(name);
    }





參考鏈接:

http://www.reibang.com/p/5f79217f2e18
https://nomico271.github.io/2017/07/07/JVM%E7%B1%BB%E5%8A%A0%E8%BD%BD%E6%9C%BA%E5%88%B6/
https://www.cnblogs.com/gdpuzxs/p/7044963.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末焰雕,一起剝皮案震驚了整個(gè)濱河市姜胖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌淀散,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚜锨,死亡現(xiàn)場(chǎng)離奇詭異档插,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)亚再,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)郭膛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人氛悬,你說(shuō)我怎么就攤上這事则剃。” “怎么了如捅?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵棍现,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我镜遣,道長(zhǎng)己肮,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任悲关,我火速辦了婚禮谎僻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘寓辱。我一直安慰自己艘绍,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布秫筏。 她就那樣靜靜地躺著诱鞠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪跳昼。 梳的紋絲不亂的頭發(fā)上般甲,一...
    開(kāi)封第一講書(shū)人閱讀 51,624評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音鹅颊,去河邊找鬼敷存。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的锚烦。 我是一名探鬼主播觅闽,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼涮俄!你這毒婦竟也來(lái)了蛉拙?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤彻亲,失蹤者是張志新(化名)和其女友劉穎孕锄,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體苞尝,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡畸肆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了宙址。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片轴脐。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖抡砂,靈堂內(nèi)的尸體忽然破棺而出大咱,到底是詐尸還是另有隱情,我是刑警寧澤注益,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布碴巾,位于F島的核電站,受9級(jí)特大地震影響丑搔,放射性物質(zhì)發(fā)生泄漏餐抢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一低匙、第九天 我趴在偏房一處隱蔽的房頂上張望旷痕。 院中可真熱鬧,春花似錦顽冶、人聲如沸欺抗。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)绞呈。三九已至,卻和暖如春间景,著一層夾襖步出監(jiān)牢的瞬間佃声,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工倘要, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留圾亏,地道東北人十拣。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像志鹃,于是被迫代替她去往敵國(guó)和親夭问。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 有一句名言:熟悉的地方?jīng)]有風(fēng)景曹铃。人們總是希望生活在美景如畫(huà)的地方缰趋,可是哪一個(gè)地方會(huì)給人的感覺(jué)永遠(yuǎn)美麗?我們?nèi)ツ吧?..
    蕭垠閱讀 428評(píng)論 0 0
  • 飯量說(shuō)力量 廉頗老矣,尚能飯否评甜? 一飯斗米肉十斤直撤,按現(xiàn)在的重量折合大約就是三斤米五斤肉,廉頗年輕時(shí)日常每頓的飯量大...
    百家載閱讀 1,272評(píng)論 1 4
  • 今天好累蜕着,洗洗睡了!
    日月升歌閱讀 206評(píng)論 0 0
  • 今天一路逛奔红柱。下午3點(diǎn)趕飛機(jī)承匣,5點(diǎn)到達(dá)三亞鳳凰機(jī)場(chǎng)。出租車(chē)锤悄、高鐵韧骗、滴滴打車(chē),全用上零聚,終于到達(dá)目的地袍暴,陵水縣英洲...
    幾點(diǎn)周閱讀 172評(píng)論 0 0