從 深入淺出“類加載器” 一文中我已經(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 源碼詳解