啓動類加載器 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); } 複製代碼