Java虛擬機自帶的類加載器
BootStrap ClassLoader(啟動/根類加載器)
是由底層虛擬機來加載的類加載器桥胞,該類加載器無父加載器恳守。由它來加載Java語言的核心類庫,如java.lang等包下的類贩虾,因此java.lang.Object也是由該加載器來加載催烘。默認情況下該加載器是根據(jù)系統(tǒng)屬性sun.boot.class.path來加載對應(yīng)類庫,一般情況下主要是rt.jar中的文件缎罢。該類加載器的實現(xiàn)依賴底層操作系統(tǒng)伊群,是虛擬機實現(xiàn)的一部分。它并不是java.lang.ClassLoader的子類策精,它是由C++編寫的舰始。
注意,如果隨意修改sun.boot.class.path這個系統(tǒng)屬性咽袜,可能導(dǎo)致無法加載java.lang.Object這個類從而造成虛擬機啟動失敗丸卷。
Extension ClassLoader(擴展類加載器)
它是純Java編寫的,是java.lang.ClassLoader的子類询刹。由BootStrap ClassLoader來加載谜嫉,從層級結(jié)構(gòu)上來看是BootStrap ClassLoader的下級,它從java.ext.dir位置處加載類范抓,或者從JDK安裝路徑下jre/lib/ext目錄下加載類骄恶。如果用戶將自己的jar放在這個路徑下也會由擴展類加載器來加載。
App ClassLoader(應(yīng)用/系統(tǒng)類加載器)
又稱系統(tǒng)類加載器匕垫,原因是在ClassLoader類中的getSystemClassLoader()方法獲取到的就是AppClassLoader,因此也叫系統(tǒng)類加載器虐呻。從層級結(jié)構(gòu)上來看象泵,他是Ext ClassLoader的下級,同時默認情況下它也是所有用戶自定義類加載器的直接上級(parent)斟叼。它從環(huán)境變量classpath或java.class.path下加載類偶惠。它也是由純Java編寫,是java.lang.ClassLoader的子類朗涩。
用戶自定義的類加載器
Java提供了抽象類java.lang.ClassLoader忽孽,所有自定義類加載器都需要繼承java.lang.ClassLoader,用戶可以自定義加載邏輯。
如何創(chuàng)建自定義類加載器
繼承java.lang.ClassLoader兄一,重寫findClass方法返回類的Class對象厘线。
雙親委托機制
什么是雙親委托機制
在雙親委托機制下,各個類加載器之間呈樹型結(jié)構(gòu)出革。除了根類加載器之外造壮,其他類加載器有且只有一個雙親(parent)。而根類加載器在HotSpot虛擬機中的parent為null骂束。其示意圖如下:
BootStrapClassLoader
? ↑
? |
? ExtClassLoader
? ↑
? |
? AppClassLoader
? ↑
? |
用戶自定義的ClassLoader
在需要加載類時從下往上依次委托耳璧,當某個ClassLoader需要加載某個類時,首先是使用parent類加載器來加載展箱,parent類加載器拿到這個加載請求后繼續(xù)轉(zhuǎn)交給自己的parent旨枯,直到根類加載器,由根類加載器開始加載混驰,如果無法加載該類則向下返回召廷,從上往下依次加載,直到加載成功或失敗拋出ClassNotFoundException账胧。
雙親委托機制的優(yōu)缺點
優(yōu)點
雙親委托機制可以明顯的提高軟件的安全性竞慢,因為用戶自定義的類加載器永遠不可能加載到本該有parent加載器來加載的可靠類,從而防止不可靠甚至是惡意代碼代替了父加載器加載的可靠代碼治泥,例如java.lang.Object類是由根類加載器來加載的筹煮,因此其他任何自定義的類加載器都無法加載含有惡意代碼的java.lang.Object類。
缺點
缺點是在應(yīng)對SPI這種情況時會造成無法加載實現(xiàn)類的問題居夹。
雙親委托機制中存在一個隱含的關(guān)系是一個類是由某個類加載器加載的败潦,那么它所引用的其他類都是由該類加載器來加載,例如JDBC中Driver接口是由根類加載器加載的准脂,那么在正常情況下它的實現(xiàn)類也會由根類加載器來加載劫扒,當正常情況下實現(xiàn)類都是廠商提供的jar包,我們一般會放在classpath中狸膏,因此需要使用應(yīng)用類加載器來加載沟饥。這時就需要使用線程上下文類加載器(Thread.currentThread().getContextClassLoader())來解決。借助這種機制可以打破雙親委托機制限制湾戳。典型的示例是ServiceLoader中實現(xiàn)贤旷。感興趣可以自己參考ServiceLoader的實現(xiàn)過程。
類加載器的命名空間
什么是命名空間
每個類加載器都有自己的命名空間砾脑,命名空間由該類加載器及其所有父類加載器說加載的所有類構(gòu)成
命名空間的特點
在同一個命名空間中不會存在類的完整名稱完全相同的兩個類幼驶,但在不同命名空間中可以存在。因此如果兩個類在不同命名空間中相互調(diào)用韧衣,會報ClassCastException盅藻,即使兩個類實際上是同一個類购桑。
命名空間的可見性
根據(jù)命名空間的定義可以知道
- 如果兩個類之間沒有明確的父子關(guān)系,那么他們的命名空間是相互不可見的氏淑。
- 另外由于子加載器的命名空間包含了所有父類加載的所加載的類勃蜘,因此父類加載器的命名空間對子類加載器的命名空間是可見的。
- 同理可知子類加載器的命名空間對父類加載器是不可見的