參考鏈接:https://blog.csdn.net/briblue/article/details/54973413
三大類加載器與各自加載的包,執(zhí)行順行
Bootstrap ClassLoader 最頂層的加載類,主要加載核心類庫募舟,%JRE_HOME%\lib下的rt.jar部蛇、resources.jar辽聊、charsets.jar和class等靡砌。另外需要注意的是可以通過啟動jvm時指定-Xbootclasspath和路徑來改變Bootstrap ClassLoader的加載目錄扩然。比如java -Xbootclasspath/a:path被指定的文件追加到默認的bootstrap路徑中觅闽。我們可以打開我的電腦帝雇,在上面的目錄下查看,看看這些jar包是不是存在于這個目錄蛉拙。
Extention ClassLoader 擴展的類加載器尸闸,加載目錄%JRE_HOME%\lib\ext目錄下的jar包和class文件。還可以加載-D java.ext.dirs選項指定的目錄孕锄。
Appclass Loader 也稱為SystemAppClass 加載當前應用的classpath的所有類
加載順序:
1. Bootstrap CLassloder
2. Extention ClassLoader
3. AppClassLoader
測試Bootstrap CLassloder 加載的東西
System.out.println(System.getProperty("sun.boot.class.path"));
結果:
C:\Program Files\Java\jre1.8.0_91\lib\resources.jar;
C:\Program Files\Java\jre1.8.0_91\lib\rt.jar;
C:\Program Files\Java\jre1.8.0_91\lib\sunrsasign.jar;
C:\Program Files\Java\jre1.8.0_91\lib\jsse.jar;
C:\Program Files\Java\jre1.8.0_91\lib\jce.jar;
C:\Program Files\Java\jre1.8.0_91\lib\charsets.jar;
C:\Program Files\Java\jre1.8.0_91\lib\jfr.jar;
C:\Program Files\Java\jre1.8.0_91\classes
測試Extention ClassLoader 加載的東西
System.out.println(System.getProperty("java.ext.dirs"));
結果:
C:\Program Files\Java\jre1.8.0_91\lib\ext;C:\Windows\Sun\Java\lib\ext
測試AppClassLoader 加載的東西
System.out.println(System.getProperty("java.class.path"));
結果:
D:\workspace\ClassLoaderDemo\bin
這個路徑其實就是當前java工程目錄bin吮廉,里面存放的是編譯生成的class文件,java工程中的bin目錄一般存放的都是編譯.java文件生成的二進制.class可執(zhí)行文件
查看類記載器
執(zhí)行代碼:
public class Hello {
public static void main(String[] args) {
ClassLoader cl = Hello.class.getClassLoader();
System.out.println("ClassLoader is:"+cl.toString());
}
}
結果:
ClassLoader is:jdk.internal.loader.ClassLoaders$[AppClassLoader@4f8e5cde](mailto:AppClassLoader@4f8e5cde)
也就是說明Hello.class文件是由AppClassLoader加載的畸肆,而像int.class宦芦,string.class是由Bootstrap ClassLoader加載的
每個類加載器都有一個父加載器(父加載器不是父類)
查看AppClassLoader的父加載器,執(zhí)行代碼:
public static void main(String[] args) {
ClassLoader cl = Hello.class.getClassLoader();
System.out.println("ClassLoader\'s parent is:"+cl.getParent().toString());
}
結果:
ClassLoader's parent is:jdk.internal.loader.ClassLoaders$[PlatformClassLoader@311d617d](mailto:PlatformClassLoader@311d617d)
這個說明恼除,AppClassLoader的父加載器是ExtClassLoader踪旷,ExtClassLoader的parent是null
類圖比較
Bootstrap ClassLoader是由C++編寫的曼氛。
Bootstrap ClassLoader是由C++編寫的。
Bootstrap ClassLoader是由C/C++編寫的令野,它本身是虛擬機的一部分舀患,所以它并不是一個JAVA類,也就是無法在java代碼中獲取它的引用气破,JVM啟動時通過Bootstrap類加載器加載rt.jar等核心jar包中的class文件聊浅,之前的int.class,String.class都是由它加載。然后呢现使,我們前面已經分析了低匙,JVM初始化sun.misc.Launcher并創(chuàng)建Extension ClassLoader和AppClassLoader實例。并將ExtClassLoader設置為AppClassLoader的父加載器碳锈。Bootstrap沒有父加載器顽冶,但是它卻可以作用一個ClassLoader的父加載器。比如ExtClassLoader售碳。這也可以解釋之前通過ExtClassLoader的getParent方法獲取為Null的現(xiàn)象
雙親委托查找
一個類加載器查找class和resource時强重,是通過“委托模式”進行的,它首先判斷這個class是不是已經加載成功贸人,如果沒有的話它并不是自己進行查找间景,而是先通過父加載器,然后遞歸下去艺智,直到Bootstrap ClassLoader倘要,如果Bootstrap classloader找到了,直接返回十拣,如果沒有找到封拧,則一級一級返回,最后到達自身去查找這些對象父晶。這種機制就叫做雙親委托
用序列描述一下:
1. 一個AppClassLoader查找資源時捂龄,先看看緩存是否有逸吵,緩存有從緩存中獲取稿黄,否則委托給父加載器愧旦。
2. 遞歸,重復第1部的操作埠胖。
3. 如果ExtClassLoader也沒有加載過糠溜,則由Bootstrap ClassLoader出面,它首先查找緩存直撤,如果沒有找到的話非竿,就去找自己的規(guī)定的路徑下,也就是sun.mic.boot.class下面的路徑谋竖。找到就返回红柱,沒有找到承匣,讓子加載器自己去找。
4. Bootstrap ClassLoader如果沒有查找成功锤悄,則ExtClassLoader自己在java.ext.dirs路徑中去查找韧骗,查找成功就返回,查找不成功零聚,再向下讓子加載器找袍暴。
5. ExtClassLoader查找不成功,AppClassLoader就自己查找隶症,在java.class.path路徑下查找政模。找到就返回。如果沒有找到就讓子類找蚂会,如果沒有子類會怎么樣淋样?拋出各種異常
重要方法loadClass()
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
1. 執(zhí)行findLoadedClass(String)去檢測這個class是不是已經加載過了。
2. 執(zhí)行父加載器的loadClass方法胁住。如果父加載器為null习蓬,則jvm內置的加載器去替代,也就是Bootstrap ClassLoader措嵌。這也解釋了ExtClassLoader的parent為null,但仍然說Bootstrap ClassLoader是它的父加載器。
3. 如果向上委托父加載器沒有加載成功芦缰,則通過findClass(String)查找企巢,前面說過ExtClassLoader的parent為null,所以它向上委托時让蕾,系統(tǒng)會為它指定Bootstrap ClassLoader
要注意的是如果要編寫一個classLoader的子類浪规,也就是自定義一個classloader,建議覆蓋findClass()方法探孝,而不要直接改寫loadClass()方法
例如:
if (parent != null) {
//父加載器不為空則調用父加載器的loadClass
c = parent.loadClass(name, false);
} else {
//父加載器為空則調用Bootstrap Classloader
c = findBootstrapClassOrNull(name);
}
自定義ClassLoader
不知道大家有沒有發(fā)現(xiàn)笋婿,不管是Bootstrap ClassLoader還是ExtClassLoader等,這些類加載器都只是加載指定的目錄下的jar包或者資源顿颅。如果在某種情況下缸濒,我們需要動態(tài)加載一些東西呢?比如從D盤某個文件夾加載一個class文件粱腻,或者從網絡上下載class主內容然后再進行加載庇配,這樣可以嗎?如果要這樣做的話绍些,需要我們自定義一個classloader
自定義步驟
1.編寫一個類繼承自ClassLoader抽象類捞慌。
2.復寫它的findClass()方法。
3.在findClass()方法中調用defineClass(), 這個方法在編寫自定義classloader的時候非常重要柬批,它能將class . 二進制內容轉換成Class對象啸澡,如果不符合要求的會拋出各種異常
注意:一個ClassLoader創(chuàng)建時如果沒有指定parent袖订,那么它的parent默認就是AppClassLoader
可根據鏈接:https://blog.csdn.net/briblue/article/details/54973413查看自定義ClassLoad的例子
關鍵字 路徑
類加載器的關聯(lián)部分就是路徑,也就是要加載的class或者是資源的路徑嗅虏。
BootStrap ClassLoader洛姑、ExtClassLoader、AppClassLoader都是加載指定路徑下的jar包旋恼。如果我們要突破這種限制吏口,實現(xiàn)自己某些特殊的需求,我們就得自定義ClassLoader冰更,自已指定加載的路徑产徊,可以是磁盤、內存蜀细、網絡或者其它
常見的用法是將Class文件按照某種加密手段進行加密舟铜,然后按照規(guī)則編寫自定義的ClassLoader進行解密,這樣我們就可以在程序中加載特定了類奠衔,并且這個類只能被我們自定義的加載器進行加載谆刨,提高了程序的安全性
可根據鏈接:https://blog.csdn.net/briblue/article/details/54973413查看例子
每個Thread都有一個相關聯(lián)的ClassLoader,默認是AppClassLoader归斤。并且子線程默認使用父線程的ClassLoader除非子線程特別設置
總結
ClassLoader用來加載class文件的痊夭。
系統(tǒng)內置的ClassLoader通過雙親委托來加載指定路徑下的class和資源。
可以自定義ClassLoader一般覆蓋findClass()方法脏里。
ContextClassLoader與線程相關她我,可以獲取和設置,可以繞過雙親委托的機制