當某個類加載器需要加載某個.class
文件時,它首先把這個任務委託給他的上級類加載器,遞歸這個操作,如果上級的類加載器沒有加載,自己纔會去加載這個類。
類加載器的類別
BootstrapClassLoader(啓動類加載器)
c++
編寫,加載java
核心庫 java.*
,構造ExtClassLoader
和AppClassLoader
。由於引導類加載器涉及到虛擬機本地實現細節,開發者無法直接獲取到啓動類加載器的引用,所以不允許直接通過引用進行操作
ExtClassLoader (標準擴展類加載器)
java
編寫,加載擴展庫,如classpath
中的jre
,javax.*
或者java.ext.dir
指定位置中的類,開發者可以直接使用標準擴展類加載器。
AppClassLoader(系統類加載器)
java
編寫,加載程序所在的目錄,如user.dir
所在的位置的class
CustomClassLoader(用戶自定義類加載器)
java
編寫,用戶自定義的類加載器,可加載指定路徑的class
文件
源碼分析
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 首先檢查這個classsh是否已經加載過了
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
// c==null表示沒有加載,如果有父類的加載器則讓父類加載器加載
if (parent != null) {
c = parent.loadClass(name, false);
} else {
//如果父類的加載器爲空 則說明遞歸到bootStrapClassloader了
//bootStrapClassloader比較特殊無法通過get獲取
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {}
if (c == null) {
//如果bootstrapClassLoader 仍然沒有加載過,則遞歸回來,嘗試自己去加載class
long t1 = System.nanoTime();
c = findClass(name);
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
委派機制的流程圖
雙親委派機制的作用
1、防止重複加載同一個.class
。通過委託去向上面問一問,加載過了,就不用再加載一遍。保證數據安全。
2、保證核心.class
不能被篡改。通過委託方式,不會去篡改核心.clas
,即使篡改也不會去加載,即使加載也不會是同一個.class
對象了。不同的加載器加載同一個.class
也不是同一個Class
對象。這樣保證了Class
執行安全。