JVM 類加載器分類
1. 前言
我們之前對類加載子系統進行過簡要的介紹,此處我們將會進行更加細致的講解。本節主要知識點如下:
- 啟動(Bootstrap)類加載器的作用及代碼驗證,為本節重點內容之一;
- 擴展(Extension)類加載器的作用及代碼驗證,為本節重點內容之一;
- 系統(System Application)類加載器的作用及代碼驗證,為本節重點內容之一。
通篇皆為重點內容,都是學習者需要重點掌握的。并且此節的內容也是后續內容的知識基礎,為了更順利的進行學習,次節內容需要重點掌握。
2. 類加載子系統知識回顧
我們在JVM 總體架構的講解過程中,提到過類加載子系統的工作流程分為三步:加載->鏈接->初始化。如下圖所示:
本節我們所討論的內容都是圍繞第一步“加載(Loading)” 進行的。對于鏈接和初始化,我們會在后邊的章節進行講解。
我們將加載(Loading)這一步,再進行下細致的模塊劃分,如下圖所示:
從上圖中我們可看到,加載(loading)這一步,里邊包含了三個更加細粒度的模塊,分別為 BootStrap Class Loader,Extention Class Loader 和 Application Class Loader,這三個 Class Loader 就是我們加載過程中必須要使用到的三大類加載器。
3. 啟動(Bootstrap)類加載器
定義:啟動(Bootstrap)類加載器也稱為引導類加載器,該加載器是用本地代碼實現的類加載器,它所加載的類庫絕大多數都是出自 %JAVA_HOME%/lib 下面的核心類庫,當然還有其他少部分所需類庫。
由于引導類加載器涉及到虛擬機本地實現細節,開發者無法直接獲取到啟動類加載器的引用,所以不允許直接通過引用進行操作。
Tips:從上述定義的描述中,我們可以看到一個特別需要關注的點:啟動類加載器加載的絕對大多數是 %JAVA_HOME%/lib 下邊的核心類庫。這句話完完全全的體現出了啟動(Bootstrap)類加載器存在的意義。對于其他少部分核心類的加載,我們在代碼驗證過程中來講解。接下來,讓我們通過示例代碼進行下驗證。
示例:通過編寫一個 main 函數,打印出通過啟動(Bootstrap)類加載器加載的所有的類庫信息,以證實啟動(Bootstrap)類加載器加載的是 %JAVA_HOME%/lib 下邊的核心類庫。
Tips:注意下 main 函數代碼的第二行代碼
URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
這是通過 sun 公司提供的 Launcher 包獲取 Bootstrap 類加載器下 ClassPath 下的所有的 URL。
import java.net.URL;
public class LoaderDemo {
public static void main(String[] args) {
System.out.println("BootstrapClassLoader 的加載路徑: ");
URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
for(URL url : urls)
System.out.println(url);
}
}
結果驗證:運行 main 函數。
Tips:此處運行結果所打印的類庫的絕對路徑為本人本機的安裝路徑,學習者應按照自己真實的JDK安裝路徑以及版本對號入座,此處僅為示例。
BootstrapClassLoader 的加載路徑:
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/resources.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/rt.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/sunrsasign.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/jsse.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/jce.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/charsets.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/jfr.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/classes
結果解析:我們可以看到,運行結果中的前 7 個類庫(不同的JDK版本會有差異,此處我們討論的是JDK 1.8版本),都是出自lib下的核心類庫。但是對于最后一條加載信息卻不是 lib 下的類庫。我們仔細看下最后這條信息的加載 file:/D:/Programs/Java/jdk1.8.0_111/jre/classes。
這就是前文我們所提到的其他少部分的核心類庫加載,學習者可以根據自己真實的安裝位置打開 /jre 文件夾,看看是否存在 /classes 路徑。結果是 /classes 文件夾路徑并不存在,除非我們進行特殊的參數創建才可以出現 /classes 路徑。此處并非我們主要討論的問題,我們關注的是lib文件夾下的核心類庫加載,這里僅做了解即可。
4. 擴展(Extension)類加載器
定義:擴展類加載器是由 Sun 公司提供的 ExtClassLoader(sun.misc.Launcher$ExtClassLoader)實現的,它負責將 %JAVA_HOME%/lib/ext 或者少數由系統變量 -Djava.ext.dir 指定位置中的類庫加載到內存中。開發者可以直接使用標準擴展類加載器。
Tips:此處我們依舊對大多數的核心類庫加載位置進行討論,即 %JAVA_HOME%/lib/ext 文件夾下的擴展核心類庫。對于系統變量指定的類庫,稍作了解即可。下邊進行示例代碼驗證
示例:
import java.net.URL;
import java.net.URLClassLoader;
public class LoaderDemo {
public static void main(String[] args) {
//取得擴展類加載器
URLClassLoader extClassLoader = (URLClassLoader)ClassLoader.getSystemClassLoader().getParent();
System.out.println(extClassLoader);
System.out.println("擴展類加載器 的加載路徑: ");
URL[] urls = extClassLoader.getURLs();
for(URL url : urls)
System.out.println(url);
}
}
結果驗證:運行 main 函數。
擴展類加載器 的加載路徑:
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/access-bridge-64.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/cldrdata.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/dnsns.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/jaccess.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/jfxrt.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/localedata.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/nashorn.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/sunec.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/sunjce_provider.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/sunmscapi.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/sunpkcs11.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/zipfs.jar
結果解析:我們可以看到,運行結果中所有的核心類庫均來自 %JAVA_HOME%/lib/ext 的文件夾。
5. 系統(System Application)類加載器
定義:系統類加載器是由 Sun 公司提供的 AppClassLoader(sun.misc.Launcher$AppClassLoader)實現的,它負責將 用戶類路徑(java -classpath或-Djava.class.path變量所指的目錄,即當前類所在路徑及其引用的第三方類庫的路徑)下的類庫加載到內存中。開發者可以直接使用系統類加載器。
Tips:系統(System Application)類加載器加載的核心類庫類型比較多,也會加載 lib 下的未被 BootStrap 類加載器加載的類庫,還會加載 ext 文件夾下的未被 Extension 類加載器加載的類庫,以及其他類庫??偠灾痪湓挘虞d除了 BootStrap 類加載器和 Extension 類加載器所加載的其余的所有的核心類庫。
示例:
import java.net.URL;
import java.net.URLClassLoader;
public class LoaderDemo {
public static void main(String[] args) {
//取得應用(系統)類加載器
URLClassLoader appClassLoader = (URLClassLoader)ClassLoader.getSystemClassLoader();
System.out.println(appClassLoader);
System.out.println("應用(系統)類加載器 的加載路徑: ");
URL[] urls = appClassLoader.getURLs();
for(URL url : urls)
System.out.println(url);
}
}
結果驗證:運行 main 函數。
應用(系統)類加載器 的加載路徑:
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/charsets.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/deploy.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/access-bridge-64.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/cldrdata.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/dnsns.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/jaccess.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/jfxrt.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/localedata.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/nashorn.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/sunec.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/sunjce_provider.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/sunmscapi.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/sunpkcs11.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/ext/zipfs.jar
file/D:/Programs/Java/jdk1.8.0_111/jre/lib/javaws.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/jce.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/jfr.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/jfxswt.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/jsse.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/management-agent.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/plugin.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/resources.jar
file:/D:/Programs/Java/jdk1.8.0_111/jre/lib/rt.jar
file:/E:/IdeaWorkspace/LeeCode/target/classes/
file:/D:/Programs/IntelliJ%20IDEA%20Educational%20Edition%202019.3.1/lib/idea_rt.jar
結果解析:我們可以看到, 系統(System Application)類加載器加載的類庫種類很多,除了之前兩種類加載器加載的類庫,其余必須的核心類庫,都由系統類加載器加載。
6. 小結
對于類加載器中的第一步加載(Loading),我們主要講解了 3 種類加載器。并且對不同的類加載器所加載的類庫進行了講解以及代碼驗證。通篇皆為重點知識,需要學習者用心學習。
對于加載(Loading)這一步,我們還未講解完,下節課程會講解加載(Loading)這一步所遵循的雙親委派模型,本節作為下一節的知識基礎,更需要著重理解、掌握。