JVM——三個ClassLoader詳解


  類裝載工作由ClassLoader及其子類負責,ClassLoader是一個重要的Java執行時系統組件,它負責在運行時查找和裝入Class字節碼文件。JVM在運行時會產生三個ClassLoader:根裝載器ExtClassLoader(擴展類裝載器)和AppClassLoader(系統類裝載器)。其中,根裝載器不是ClassLoader的子類,它使用C++編寫,因此我們在Java中看不到它,根裝載器負責裝載JRE的核心類庫,如JRE目標下的rt.jar、charsets.jar等。ExtClassLoader和AppClassLoader都是ClassLoader的子類。其中ExtClassLoader負責裝載JRE目錄ext中的JAR類包;AppClassLoader負責裝載ClassPath路徑下的類包。

  • 啟動類加載器(Bootstrap ClassLoader):這個類加載器負責將存放在<JAVA_HOME>\lib目錄中的。啟動類加載器無法被Java程序直接引用,用戶在編寫自定義類加載器時,如果需要把加載請求委派給引導類加載器,那直接使用null代替即可。
  • 擴展類加載器(Extension ClassLoader):這個加載器由sun.misc.Launcher$ExtClassLoader實現,它負責加載<JAVA_HOME>\lib\ext目錄中的,或者被java.ext.dirs系統變量所指定的路徑中的所有類庫,開發者可以直接使用擴展類加載器。
  • 應用程序類加載器(Application ClassLoader):這個類加載器由sun.misc.Launcher$AppClassLoader實現。由於這個類加載器是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也稱它為系統類加載器。它負責加載用戶類路徑(ClassPath)上所指定的類庫,開發者可以直接使用這個類加載器,如果應用程序中沒有自定義自己的類加載器,一般情況下這個就是程序中默認的類加載器。

  我們的應用程序都是由這3種類加載器互相配合進行加載的,如果有必要,還可以加入自己定義的類加載器。這些類加載器之間的關系一般為:

  上圖展示的類加載器之間的這種層次關系,稱為類加載器的雙親委派模型。雙親委派模型要求除了頂層的啟動類加載器外,其余的類加載器都應當有自己的父類加載器。這里類加載器之間的父子關系一般不會以繼承的關系來實現,而是都使用組合關系來復用父加載器的代碼。

  類加載器的雙親委派模型詳解博客鏈接

  這三個類裝載器之間存在父子層級關系,即根裝載器是ExtClassLoader的父裝載器,ExtClassLoader是父類裝載器。默認情況下,使用AppClassLoader裝載應用程序的類,用以下代碼證明:

 1 /**
 2  * @author zhengbinMac
 3  */
 4 public class ClassLoaderTest {
 5 
 6     public static void main(String[] args) {
 7         ClassLoader loader = Thread.currentThread().getContextClassLoader();
 8         System.out.println("current loader:" + loader);
 9         System.out.println("parent loader:" + loader.getParent());
10         System.out.println("grandparent loader:" + loader.getParent().getParent());
11     }
12     /*
13      * output:
14      *    current loader:sun.misc.Launcher$AppClassLoader@1b6d3586
15      *    parent loader:sun.misc.Launcher$ExtClassLoader@1540e19d 
16      *    grandparent loader:null // 因為根類裝載器在Java中訪問不到,所有返回null
17      */
18 }

  Thread.currentThread():返回對當前正在執行的線程對象的引用。

  getContextClassLoader():返回該線程的上下文 ClassLoader。

  通過以上的輸出信息,可以明白,ClassLoader是AppClassLoader,父ClassLoader是ExtClassLoader,祖父ClassLoader是根類裝載器,因為在Java中無法獲得它的句柄,所以直接返回null。

  除了JVM默認的三個ClassLoader以外,可以編寫自己的第三方類裝載器,以實現一些特殊的需求。類文件被裝載並解析后,在JVM內將擁有一個對應的java.lang.Class類描述對象,該類的實例都擁有指向這個類描述對象的引用,而類描述對象又擁有指向關聯ClassLoader的引用。如下圖所示:

ClassLoader重要方法


  在Java中,ClassLoader是一個抽象類,位於java.lang包中。下面對該類的一些重要接口方法進行介紹:

  • Class loadClass(String name)

  name參數指定類裝載器需要裝載類的名字,必須使用全限定類名,如com.zhengbin.entity.Student。該方法有一個重載方法loadClass(String name, boolean resolve),resolve參數告訴類裝載器是否需要解析該類。在初始化類之前,應考慮進行類解析的工作,但並不是所有的類都需要解析,如果JVM只需要知道該類是否存在或找出該類的超類,那么就不需要進行解析。

  • Class defineClass(String name, byte[] b, int off, int len)

  將類文件的字節數組轉換成JVM內部的java.lang.Class對象。字節數組可以從本地文件系統、遠程網絡獲取。name為字節數組對應的全限定類名。

  • Class findSystemClass(String name)

  從本地文件系統載入Class文件,如果本地文件系統不存在該Class文件,將拋出ClassNotFoundException異常。該方法是JVM默認使用的裝載機制。

  • ClassLoader getParent()

  獲取類裝載器的父裝載器,除根裝載器外,所有的類裝載器都有且僅有一個父裝載器,ExtClassLoader的父裝載器是根裝載器,因為根裝載器非Java編寫,所以無法獲得,將返回null。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM