JVM自帶載入器
- 啟動類載入器 BootStrap ClassLoader:最頂層的類載入器,負責載入 JAVA_HOME\lib 目錄中的,或通過-Xbootclasspath引數指定路徑中的,且被虛擬機器認可(按檔名識別,如rt.jar)的類。可以通
System.getProperty("sun.boot.class.path")
檢視載入的路徑。 - 擴充套件類載入器 Extention ClassLoader:主要載入目錄
%JRE_HOME%\lib\ext
目錄下的jar
包和class
檔案,或通過java.ext.dirs系統變數指定路徑中的類庫。也可以通過System.out.println(System.getProperty("java.ext.dirs"))
檢視載入類檔案的路徑。 - 應用程式類載入器 Application ClassLoader:也叫做系統類載入器,可以通過
getSystemClassLoader()
獲取,負責載入使用者路徑classpath
上的類庫。如果沒有自定義類載入器,一般這個就是預設的類載入器。
類載入層次關係
類載入器之間的這種層次關係叫做雙親委派模型。
雙親委派模型要求除了頂層的啟動類載入器(Bootstrap ClassLoader)外,其餘的類載入器都應當有自己的父類載入器。這裡的類載入器之間的父子關係一般不是以繼承關係實現的,而是用組合實現的。
- 下面看一段原始碼
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
初始化的時候建立了ExtClassLoader
以及AppClassLoader
,並將ExtClassLoader
例項傳入到AppClassLoader
中。
(2)雖然上一段原始碼中沒見到建立BoopStrap ClassLoader
,但是程式一開始就執行了System.getProperty("sun.boot.class.path")
。
附上
Launcher
相關文章:blog.csdn.net/jyxmust/art…
- 類載入器中的繼承關係
AppClassLoader
的父載入器為ExtClassLoader
,ExtClassLoader
的父載入器為null
,BoopStrap ClassLoader
為頂級載入器。
類載入機制-雙親委託
當JVM載入Test.class
類的時候
- 首先會到自定義載入器中查詢,看是否已經載入過,如果已經載入過,則返回該類。
- 如果自定義載入器沒有載入過,則詢問上一層載入器(即
AppClassLoader
)是否已經載入過Test.class
。 - 如果沒有載入過,則詢問上一層載入器(
ExtClassLoader
)是否已經載入過。 - 如果沒有載入過,則繼續詢問上一層載入(
BoopStrap ClassLoader
)是否已經載入過。 - 如果
BoopStrap ClassLoader
沒有載入過,則到自己指定類載入路徑sun.boot.class.path
下檢視是否有Test.class
位元組碼,有則載入並返回載入後的類c = findBootstrapClassOrNull(name)
。 - 如果還是沒找到呼叫
c = findClass(name)
到載入器ExtClassLoader
指定的類載入路徑java.ext.dirs
下查詢class
檔案,有則載入並返回類。 - 依此類推,最後到自定義類載入器指定的路徑還沒有找到
Test.class
位元組碼,則丟擲異常ClassNotFoundException
。
這裡注意
每個自定義的類載入器都需要重寫findClass
方法,該方法的作用是到指定位置查詢class
檔案並載入到JVM中,如果找不到則丟擲ClassNotFoundException
異常。
雙親委派模型最大的好處就是讓Java類同其類載入器一起具備了一種帶優先順序的層次關係。這句話可能不好理解,我們舉個例子。比如我們要載入頂層的Java類——
java.lang.Object
類,無論我們用哪個類載入器去載入Object
類,這個載入請求最終都會委託給Bootstrap ClassLoader
,這樣就保證了所有載入器載入的Object
類都是同一個類。
雙親委派模型的實現比較簡單,在java.lang.ClassLoader
的loadClass
方法中:
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);
}
複製程式碼
參考連結:
www.jianshu.com/p/5f79217f2…
nomico271.github.io/2017/07/07/…
www.cnblogs.com/gdpuzxs/p/7…