類加載器
對類加載器的學(xué)習(xí)重點(diǎn)要掌握以下幾點(diǎn):
- 雙親委派模型的概念
- 雙親委派模型的實現(xiàn)原理
- 類加載器的工作原理
- 如何使用自定義類加載器
雙親委派模型
概念
雙親委派模型是Java中默認(rèn)的類加載器模型,JDK中自帶有三個類加載器 BootstrapClassLoader、ExtClassLoader、AppClassLoader。以最常用的AppClassLoader角度來看,所有由AppClassLoader發(fā)起的類加載動作,最終都會委派給ExtClassLoader或者BootstrapClassLoader,雙親委派名稱也是由此得來。
模型的構(gòu)建
雙親委派模型是在sun.misc.Launcher類中構(gòu)建的,Launcher類是JVM實例啟動的入口。來看下該類的構(gòu)造函數(shù)代碼:
public Launcher() {
Launcher.ExtClassLoader var1;
try {
var1 = Launcher.ExtClassLoader.getExtClassLoader();
} catch (IOException var10) {
throw new InternalError("Could not create extension class loader");
}
try {
this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
} catch (IOException var9) {
throw new InternalError("Could not create application class loader");
}
Thread.currentThread().setContextClassLoader(this.loader);
//省略以下代碼...
}
從上面這段代碼可以看出,JVM實例啟動之后就馬上構(gòu)建了ExcClassLoader和AppClassLoader的實例,而這兩個ClassLoader都是以靜態(tài)內(nèi)部類的形式定義Launcher類中的。getExtClassLoader這個方法的核心代碼只有一行,就是調(diào)用ExtClassLoader類的構(gòu)造器,而其構(gòu)造器中的代碼也是非常簡潔的:
public ExtClassLoader(File[] var1) throws IOException {
super(getExtURLs(var1), (ClassLoader)null, Launcher.factory);
}
其中,第二個參數(shù)null就是其父ClassLoader,之所以是null是由于ExtClassLoader的父類加載器BootstrapClassLoader是由C++實現(xiàn)的,在Java中無法直接引用。
接下來調(diào)用AppClassLoader.getAppClassLoader(ClassLoader parent),用來構(gòu)建AppClassLoader的實例,參數(shù)傳入的父類加載器就是之前獲取到的ExtClassLoader對象。
另外最下面一行代碼,設(shè)置了線程上下文類加載器,也是AppClassLoader的實例。
類加載器的執(zhí)行過程
通過ExtClassLoader和AppClassLoader類的聲明我們可以知道,這兩個類加載器的類定義都是直接繼承于URLClassLoader,間接繼承了ClassLoader類。
默認(rèn)情況下,程序中使用的類加載器大多都是AppClassLoader,所以先從AppClassloader的loadClass方法看起。其核心代碼只有一行,就是調(diào)用父類的loadClass方法,通過追蹤代碼可以看出最終調(diào)用的是ClassLoader類中的loadClass方法,看一下loadClass中的代碼:
Class c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
}
if (c == null) {
c = findClass(name);
}
}
通過上面的代碼可以看到,對于AppClassLoader初次加載某類的情況,會先調(diào)用其父類加載器,也就是ExtClassLoader的loadClass方法去加載,而ExtClassLoader.loadClass最終執(zhí)行的也是上面這段代碼,它會進(jìn)一步調(diào)用BootstrapClassLoader去加載類。如果AppClassLoader和ExtClassLoader都沒能加載到,代碼就會繼續(xù)往下走,調(diào)用AppClassLoader的findClass方法,由于AppClassLoader沒有實現(xiàn)findClass方法,所以會調(diào)用其父類URLClassLoader的findClass方法。
自定義類加載器
首先,自定義的類加載器,必須ClassLoader的子類,可以實現(xiàn)其findClass方法或者loadClass方法。
那么,兩者有什么區(qū)別呢?通過上面的分析我們可以發(fā)現(xiàn),Java中默認(rèn)的類加載機(jī)制是維護(hù)在ClassLoader.loadClass方法中的,所以為了確保類加載模型的一致,
推薦自定義的類加載器重寫findClass方法。當(dāng)然,在一些特殊的場景下,也可能需要重寫loadClass方法來實現(xiàn)一些特定的功能,例如tomcat6中的WebappClassLoader