Java類載入原始碼閱讀
- 啟動類載入器 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
相關文章: ofollow,noindex">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>. * * @paramname *The <a href="#name">binary name</a> of the class * * @returnThe resulting <tt>Class</tt> object * * @throwsClassNotFoundException *If the class could not be found * * @since1.2 */ protected Class<?> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name); } 複製程式碼