java类二次加载_深入理解java之类加载器
一、類與類加載器
類加載器:實(shí)現(xiàn)加載階段的第一步,通過一個(gè)類的全限定名來將這個(gè)類的二進(jìn)制字節(jié)流加載進(jìn)jvm。
類與類加載器:任意一個(gè)類唯一性都是由它本身和加載它的類加載器確定,兩個(gè)類是否相等在它們是由同一個(gè)類加載器加載的前提下。
jvm虛擬機(jī)中包括兩種類加載器:一種是啟動(dòng)類加載器(Bootstrap ClassLoader),它是使用C++實(shí)現(xiàn);另一種是其他所有用java實(shí)現(xiàn)的類加載器。
從java程序角度:
1)啟動(dòng)類加載器:負(fù)責(zé)加載\lib目錄下或者被-Xbootclasspath參數(shù)所指定的路徑中的類,此外要求文件名被虛擬機(jī)識別,如果不被jvm識別也無法被加載。
2)擴(kuò)展類加載器:負(fù)責(zé)加載\lib\exit目錄下或者被java.exit.dirs系統(tǒng)變量所指定的路徑中的所有類庫。
3)應(yīng)用程序類加載器(系統(tǒng)類加載器):它是Classloader中的getSystemClassloader()方法的返回值。負(fù)責(zé)加載用戶類路徑上所指定的類庫,如果應(yīng)用程序中沒有自定義類加載器,這個(gè)就為程序中默認(rèn)的類加載器。
免費(fèi)在線視頻教學(xué):java視頻教程
二、雙親委派模型
除了頂層的啟動(dòng)類加載器,其余所有類加載器都有自己的父類加載器。父子關(guān)系不以繼承實(shí)現(xiàn),而是以組合關(guān)系來復(fù)用父類加載器。
工作過程: 類加載器接到類加載請求–>將請求委派給父類加載器(直到最頂層啟動(dòng)類加載器)–>父類嘗試加載,加載失敗反饋給子類加載器–>子類加載器嘗試加載
雙親委派模型的好處:保證java底層API的穩(wěn)定,避免加載和基本類重名(Object)的自定義類導(dǎo)致出現(xiàn)多個(gè)不同的重名的類(Object),從而造成java基礎(chǔ)行為的混亂。
雙親委派模型源碼:
方法加同步鎖保證線程安全,首先檢查該類是否被加載過,如果沒有加載則調(diào)用父類加載器的loadClass()方法,若父類加載器為空說明是啟動(dòng)類加載器,則調(diào)用啟動(dòng)類加載器。
如果父類加載失敗會(huì)拋出ClassNotFoundException,在調(diào)用自己的findClass()方法進(jìn)行加載。protected Class> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
//同步鎖
synchronized (getClassLoadingLock(name)) {
// 首先檢車這個(gè)類是不是已被加載
Class> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
//如果父類不為空則調(diào)用父類加載器的loadClass方法
c = parent.loadClass(name, false);
} else {
//沒有父類則默認(rèn)調(diào)用啟動(dòng)類加載器加載
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
//如果父類加載器找不到這個(gè)類則拋出ClassNotFoundException
}
if (c == null) {
// 父類加載器失敗時(shí)調(diào)用自身的findClass方法加載
long t1 = System.nanoTime();
c = findClass(name);
//記錄
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
三、破壞雙親委派模型
1.第一次破壞
雙親委派模型出現(xiàn)在JDK1.2之后,而類加載器和抽象類java.lang.ClassLoader已經(jīng)存在。
因此為了向前兼容,JDK1.2之后在ClassLoader中添加了一個(gè)新的protected方法findClass。用戶把自己的類加載邏輯寫在findClass方法中,而不是重寫loadClass方法,從而保證自定義的類加載符合雙親委派模型。
2.第二次破壞
模型自身有缺陷。雙親委派可以確保各個(gè)類加載器的基礎(chǔ)類的統(tǒng)一,這是在用戶代碼調(diào)用基礎(chǔ)類的情況下,如果出現(xiàn)基礎(chǔ)類回調(diào)用戶代碼那就不適用了。比如涉及到SPI的場景去加載所需要的SPI代碼。
SPI機(jī)制的介紹參考其他文章。
為了解決這個(gè)問題,引入了線程上下文加載器(Thread Context ClassLoader),這個(gè)類加載器就可以通過java.lang.Thread類中的setContextClassLoader()方法進(jìn)行設(shè)置,如果創(chuàng)建線程時(shí)未設(shè)置將會(huì)從父線程中繼承一個(gè),如果全局都沒有則默認(rèn)就是應(yīng)用程序類加載器,利用這個(gè)加載器可以完成父類加載器請求子類加載器加載的動(dòng)作。
3.第三次破壞
由于對程序動(dòng)態(tài)性追求導(dǎo)致,如熱部署,熱替換等。
比如模塊化標(biāo)準(zhǔn)OSGi R4.2中將雙親委派的樹形結(jié)構(gòu)變成了更復(fù)雜的網(wǎng)狀結(jié)構(gòu)。
java文章教程推薦:java入門教程
總結(jié)
以上是生活随笔為你收集整理的java类二次加载_深入理解java之类加载器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java hashmap 去重复_为什么
- 下一篇: Java中string字符串的值_Jav