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