從 sun.misc.Launcher 類源碼深入探索 ClassLoader

深入淺出“類加載器” 一文中我已經(jīng)通過(guò)大量的理論和示例對(duì)ClassLoader有了深入的了解。該文虽画,我們將從 sun.misc.Launcher 源碼對(duì) ClassLoader 進(jìn)行進(jìn)一步的探索,也是除了示例外的另一個(gè)更本質(zhì)的角度來(lái)驗(yàn)證我們之前說(shuō)的理論贯卦。

“擴(kuò)展類加載器”和“應(yīng)用類加載器”以及“自定義類加載器”都是由“啟動(dòng)類加載器”加載的捂齐。

首先,無(wú)論是“系統(tǒng)類加載器”還是“擴(kuò)展類加載器”都是位于 sun.misc.Launcher绘证。但是他們的訪問(wèn)修飾符(default)導(dǎo)致我們?cè)谕饨鐭o(wú)法直接訪問(wèn)這個(gè)加載器隧膏。

# sun.misc.Launcher 類中
static class AppClassLoader extends URLClassLoader {
……
}

static class ExtClassLoader extends URLClassLoader {
……
}

因?yàn)?AppClassLoader、ExtClassLoader 會(huì)在 Laucher 的構(gòu)造方法中被構(gòu)建嚷那;而 Launcher 的靜態(tài)屬性會(huì)去構(gòu)建一個(gè) Launcher 對(duì)象胞枕。而Launcher這個(gè)類在加載的時(shí)候會(huì)去加載static靜態(tài)塊,因此我們只需要明確Launcher這個(gè)類是由’啟動(dòng)類加載器’加載的魏宽。也就可以說(shuō)明’擴(kuò)展類加載器’以及’系統(tǒng)類加載器’是由’啟動(dòng)類加載器’加載的了腐泻。

# Launcher
private static Launcher launcher = new Launcher();
public Launcher() {
    Launcher.ExtClassLoader var1;
    try {
        var1 = Launcher.ExtClassLoader.getExtClassLoader();    // 構(gòu)建 擴(kuò)展類加載器
    } catch (IOException var10) {
        throw new InternalError("Could not create extension class loader", var10);
    }

    try {
        this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);    // 構(gòu)建 系統(tǒng)類加載器
    } catch (IOException var9) {
        throw new InternalError("Could not create application class loader", var9);
    }

    Thread.currentThread().setContextClassLoader(this.loader);
    String var2 = System.getProperty("java.security.manager");
    if(var2 != null) {
        SecurityManager var3 = null;
        if(!"".equals(var2) && !"default".equals(var2)) {
            try {
                var3 = (SecurityManager)this.loader.loadClass(var2).newInstance();
            } catch (IllegalAccessException var5) {
                ;
            } catch (InstantiationException var6) {
                ;
            } catch (ClassNotFoundException var7) {
                ;
            } catch (ClassCastException var8) {
                ;
            }
        } else {
            var3 = new SecurityManager();
        }

        if(var3 == null) {
            throw new InternalError("Could not create SecurityManager: " + var2);
        }

        System.setSecurityManager(var3);
    }

}

# 加載 Launcher 的類加載器
System.out.println(Launcher.class.getClassLoader());

# 控制臺(tái)
null

??由此可見(jiàn) Launcher 是由’啟動(dòng)類加載器’加載的


深入了解 ClassLoader.getSystemClassLoader() 的底層實(shí)現(xiàn)
/**
 * Returns the system class loader for delegation.  This is the default
 * delegation parent for new <tt>ClassLoader</tt> instances, and is
 * typically the class loader used to start the application.
 *
 * <p> This method is first invoked early in the runtime's startup
 * sequence, at which point it creates the system class loader and sets it
 * as the context class loader of the invoking <tt>Thread</tt>.
 *
 * <p> The default system class loader is an implementation-dependent
 * instance of this class.
 *
 * <p> If the system property "<tt>java.system.class.loader</tt>" is defined
 * when this method is first invoked then the value of that property is
 * taken to be the name of a class that will be returned as the system
 * class loader.  The class is loaded using the default system class loader
 * and must define a public constructor that takes a single parameter of
 * type <tt>ClassLoader</tt> which is used as the delegation parent.  An
 * instance is then created using this constructor with the default system
 * class loader as the parameter.  The resulting class loader is defined
 * to be the system class loader.
 *
 * <p> If a security manager is present, and the invoker's class loader is
 * not <tt>null</tt> and the invoker's class loader is not the same as or
 * an ancestor of the system class loader, then this method invokes the
 * security manager's {@link
 * SecurityManager#checkPermission(java.security.Permission)
 * <tt>checkPermission</tt>} method with a {@link
 * RuntimePermission#RuntimePermission(String)
 * <tt>RuntimePermission("getClassLoader")</tt>} permission to verify
 * access to the system class loader.  If not, a
 * <tt>SecurityException</tt> will be thrown.  </p>
 *
 * @return  The system <tt>ClassLoader</tt> for delegation, or
 *          <tt>null</tt> if none
 *
 * @throws  SecurityException
 *          If a security manager exists and its <tt>checkPermission</tt>
 *          method doesn't allow access to the system class loader.
 *
 * @throws  IllegalStateException
 *          If invoked recursively during the construction of the class
 *          loader specified by the "<tt>java.system.class.loader</tt>"
 *          property.
 *
 * @throws  Error
 *          If the system property "<tt>java.system.class.loader</tt>"
 *          is defined but the named class could not be loaded, the
 *          provider class does not define the required constructor, or an
 *          exception is thrown by that constructor when it is invoked. The
 *          underlying cause of the error can be retrieved via the
 *          {@link Throwable#getCause()} method.
 *
 * @revised  1.4
 */
@CallerSensitive
public static ClassLoader getSystemClassLoader() {
    initSystemClassLoader();
    if (scl == null) {
        return null;
    }
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkClassLoaderPermission(scl, Reflection.getCallerClass());
    }
    return scl;
}

返回一個(gè)基于委托模式的系統(tǒng)類加載器。它是新的類加載器默認(rèn)的委托父類實(shí)例队询,并且它是用于啟動(dòng)應(yīng)用的典型類加載器派桩。
首先在運(yùn)行時(shí)的啟動(dòng)序列中調(diào)用此方法,此時(shí)它會(huì)創(chuàng)建系統(tǒng)類加載器并將其設(shè)置為調(diào)用線程的上下文類加載器蚌斩。
默認(rèn)的系統(tǒng)類加載器是與這個(gè)實(shí)現(xiàn)相關(guān)的一個(gè)實(shí)例窄坦。
如果當(dāng)這個(gè)方法第一次被調(diào)用的時(shí)候,系統(tǒng)屬性”java.system.class.loader”是被定義的凳寺,那么這個(gè)屬性的值就會(huì)被作為系統(tǒng)類加載器的名字鸭津。而這個(gè)類是使用默認(rèn)的系統(tǒng)類加載器來(lái)去加載的,并且必須定義一個(gè)public的接收單個(gè)類型為ClassLoader參數(shù)的構(gòu)造方法肠缨,同時(shí)這個(gè)傳入的ClassLoader會(huì)作為委托的雙親逆趋。一個(gè)實(shí)例接下來(lái)會(huì)被創(chuàng)建通過(guò)使用這個(gè)構(gòu)造方法,同時(shí)會(huì)將默認(rèn)的系統(tǒng)類加載器作為參數(shù)傳入晒奕,而所生成的類就會(huì)被定義成’系統(tǒng)類加載器’闻书。
也就是說(shuō)名斟,默認(rèn)的情況下’系統(tǒng)類加載器’就是’AppClassLoader’,但是對(duì)于JDK來(lái)說(shuō)魄眉,如果提供了”java.system.class.loader"這個(gè)系統(tǒng)屬性砰盐,我們可以通過(guò)這個(gè)系統(tǒng)屬性來(lái)去顯示的修改“系統(tǒng)類加載器”,也就是說(shuō)讓“系統(tǒng)類加載器”不再是“AppClassLoader”坑律,而是我們自定義的某個(gè)ClassLoader岩梳。

繼續(xù)看 ClassLoader.initSystemClassLoader() 方法


『AccessController.doPrivileged(…)』: 主要是對(duì)權(quán)限的一個(gè)校驗(yàn)。你是否能這么去做晃择,或者你是否有權(quán)限這么去做冀值。

  • public static Class<?> forName(String name, boolean initialize, ClassLoader loader)
public static Class<?> forName(String name, boolean initialize,
                               ClassLoader loader)
    throws ClassNotFoundException
{
    Class<?> caller = null;
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        // Reflective call to get caller class is only needed if a security manager
        // is present.  Avoid the overhead of making this call otherwise.
        // 獲取調(diào)用當(dāng)前方法(即,forName方法)的類的 Class 對(duì)象宫屠。
        caller = Reflection.getCallerClass();
        if (sun.misc.VM.isSystemDomainLoader(loader)) {
            // 獲取’加載[調(diào)用當(dāng)前方法(即列疗,forName方法)的類的 Class 對(duì)象]’的類加載器
            ClassLoader ccl = ClassLoader.getClassLoader(caller);
            if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
                sm.checkPermission(
                    SecurityConstants.GET_CLASSLOADER_PERMISSION);
            }
        }
    }
    return forName0(name, initialize, loader, caller);
}

/** Called after security check for system loader access checks have been made. */
private static native Class<?> forName0(String name, boolean initialize,
                                        ClassLoader loader,
                                        Class<?> caller)
    throws ClassNotFoundException;

返回一個(gè)給定字符串名字的類/接口相關(guān)聯(lián)的 Class 對(duì)象。同時(shí)浪蹂,是使用給定的類加載器對(duì) Class 對(duì)象進(jìn)行加載抵栈。給定了一個(gè)類/接口完整的全限定名的話,這個(gè)方法就會(huì)嘗試的去尋找/定位坤次、加載竭讳,并鏈接類或接口。那么浙踢,這個(gè)所指定的類加載器是用于加載這個(gè)指定的類或接口的。如果‘loader’參數(shù)為 null灿渴,那么這個(gè)類就會(huì)通過(guò)’啟動(dòng)類加載器’來(lái)進(jìn)行加載洛波。這個(gè)類只有當(dāng)‘initialize’參數(shù)為 true 而且其尚未被初始化時(shí),這個(gè)類才會(huì)被初始化骚露。
如果參數(shù)‘name’表示的是一個(gè)“原生的類型”或者 “void”蹬挤,則將嘗試在名為{@code name}的未命名包中查找用戶定義的類。因此棘幸,這個(gè)方法是不能用于獲取任何表示“原生類型”或“void”的 Class 對(duì)象焰扳。
如果參數(shù)‘name’表示的是一個(gè)數(shù)組類,那么數(shù)組的’component type’就會(huì)被加載误续,但不會(huì)被初始化吨悍。

example:

* <blockquote>
*  {@code Class.forName("Foo")}
* </blockquote>
*
* is equivalent to:
*
* <blockquote>
*  {@code Class.forName("Foo", true, this.getClass().getClassLoader())}
* </blockquote>

注意,該方法并不會(huì)檢測(cè)所請(qǐng)求的類對(duì)于其調(diào)用者來(lái)說(shuō)是否可訪問(wèn)蹋嵌。
參數(shù):
a)name ———— 指定類的完整限定名
b)initialize ———— 是否初始化
c)loader ———— 用于加載指定類的類加載器

# public static Class<?> forName(String className)
public static Class<?> forName(String className)
            throws ClassNotFoundException {
    Class<?> caller = Reflection.getCallerClass();
    // 這里的 classLoader 是使用了:加載了“調(diào)用該方法的類的Class類”的類加載器育瓜。
    return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
  • 『public static Class<?> forName(String className)』與『public static Class<?> forName(String name, boolean initialize, ClassLoader loader)』的一個(gè)重要區(qū)別:
    『public static Class<?> forName(String className)』使用加載了“調(diào)用該方法的類的Class類”的類加載器;
    『public static Class<?> forName(String name, boolean initialize, ClassLoader loader)』:使用指定類加載器(即栽烂,通過(guò)參數(shù)‘loader’傳入的加載器)

相關(guān)文章

深入淺出“類加載器”
深入探索“線程上下文類加載器”
ClassLoader 源碼詳解

參考

圣思園《深入理解JVM》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末躏仇,一起剝皮案震驚了整個(gè)濱河市恋脚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌焰手,老刑警劉巖糟描,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異书妻,居然都是意外死亡船响,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門驻子,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)灿意,“玉大人,你說(shuō)我怎么就攤上這事崇呵$途纾” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵域慷,是天一觀的道長(zhǎng)荒辕。 經(jīng)常有香客問(wèn)我,道長(zhǎng)犹褒,這世上最難降的妖魔是什么抵窒? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮叠骑,結(jié)果婚禮上李皇,老公的妹妹穿的比我還像新娘。我一直安慰自己宙枷,他們只是感情好掉房,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著慰丛,像睡著了一般卓囚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上诅病,一...
    開(kāi)封第一講書(shū)人閱讀 48,970評(píng)論 1 284
  • 那天哪亿,我揣著相機(jī)與錄音,去河邊找鬼贤笆。 笑死蝇棉,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的芥永。 我是一名探鬼主播银萍,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼恤左!你這毒婦竟也來(lái)了贴唇?” 一聲冷哼從身側(cè)響起搀绣,我...
    開(kāi)封第一講書(shū)人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎戳气,沒(méi)想到半個(gè)月后链患,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瓶您,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年麻捻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呀袱。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡贸毕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出夜赵,到底是詐尸還是另有隱情明棍,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布寇僧,位于F島的核電站摊腋,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏嘁傀。R本人自食惡果不足惜兴蒸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望细办。 院中可真熱鬧橙凳,春花似錦、人聲如沸笑撞。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)娃殖。三九已至,卻和暖如春议谷,著一層夾襖步出監(jiān)牢的瞬間炉爆,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工卧晓, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留芬首,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓逼裆,卻偏偏與公主長(zhǎng)得像郁稍,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子胜宇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

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

  • 作者:成 富, 軟件工程師, IBM 中國(guó)軟件開(kāi)發(fā)中心 類加載器(class loader)是 Java?中的一個(gè)...
    Android技術(shù)研究閱讀 3,900評(píng)論 0 74
  • ClassLoader翻譯過(guò)來(lái)就是類加載器耀怜,普通的java開(kāi)發(fā)者其實(shí)用到的不多恢着,但對(duì)于某些框架開(kāi)發(fā)者來(lái)說(shuō)卻非常常見(jiàn)...
    時(shí)待吾閱讀 1,060評(píng)論 0 1
  • 類的加載指的是將類的.class文件中的二進(jìn)制數(shù)據(jù)讀入到內(nèi)存中,將其放在運(yùn)行時(shí)數(shù)據(jù)區(qū)的方法區(qū)內(nèi)财破,然后在堆區(qū)創(chuàng)建一個(gè)...
    dinel閱讀 420評(píng)論 0 0
  • 類的生命周期 類加載過(guò)程包括:加載-驗(yàn)證-準(zhǔn)備-解析-初始化掰派。這個(gè)過(guò)程順序并不是固定的,最多僅僅代表它們開(kāi)始的順序...
    jection閱讀 400評(píng)論 0 1
  • 臨近國(guó)慶,又有一大批好看的影片將要被搬上屏幕俊性,這其中略步,便有國(guó)師張藝謀的新作《影》。 《長(zhǎng)城》之后定页,他帶著自己對(duì)“武...
    海角七號(hào)地閱讀 1,257評(píng)論 5 19