Java類載入器詳解&雙親委派模式
一、Java虛擬機種的類載入器
1、類載入器種類
Java虛擬機器中可以安裝多個類載入器,系統預設三個主要的類載入器,每個類負責載入特定位置的類:
BootStrap:類載入器也是Java類,因為Java類的類載入器本身也是要被類載入器載入的,顯然必須有第一個類載入器不是Java類,這個正是BootStrap,使用C/C++程式碼寫的,已經封裝到JVM核心中了,而ExtClassLoader和AppClassLoader是Java類。
ExtClassLoader
AppClassLoader
2、類載入器的屬性結構圖及原理——雙親委派模型
類載入器的委託機制-載入原理:
1)每個類載入器載入類時,又先委託給其上級類載入器當所有祖宗類載入器沒有載入到類,回到發起者類載入器,還載入不了,則會丟擲ClassNotFoundException,不是再去找發起者類載入器的兒子,因為沒有getChild()方法。例如:如上圖所示:MyClassLoader->AppClassLoader->Ext-ClassLoader->BootStrap.自定定義的MyClassLoader1首先會先委託給AppClassLoader,AppClassLoader會委託給ExtClassLoader,ExtClassLoader
這裡需要注意的是上述三個JDK提供的類載入器雖然是父子類載入器關係,但是沒有使用繼承,而是使用了組合關係。
——上述過程即雙親委派模型:優點是java的類載入器一起具備了一種帶優先順序的層次關係,越是基礎的類,越是被上層的類載入器進行載入,保證了
2)如果類A中引用了類B,Java虛擬機器將使用載入類A的類載入器來載入類B
3)可以直接呼叫ClassLoader.loadClass(StringclassName)方法來指定某個類載入器去載入某個類
4)首先當前執行緒的類載入器去載入執行緒中的第一個類(當前執行緒的類載入器:Thread類中有一個get/setContextClassLoader(ClassLoadercl);方法,可以獲取/指定本執行緒中的類載入器)
3、例子:
輸出結果:
note:
1)因為System類,List,Map等這樣的系統提供jar類都在jre/lib/rt.jar中,所以由BootStrap類載入器載入,因為BootStrap是祖先類,不是Java編寫的,所以打印出class為null
2)將ClassLoaderTest.java打包成.jar檔案,然後將.jar檔案拷貝到Java的安裝目錄中的Java/jre7/lib/ext/目錄下,結果ClassLoaderTest的類載入器變成了ExtClassLoader,如下:
二、自定義類載入器
1、自定義的類載入器預設的都是將掛載到系統類載入器的最低端AppClassLoader:
loadClass(name,false)方法的原始碼:
執行流程是:每個類載入器:loadClass→findClass→defineClass.
findClass這個方法就是根據name來查詢到class檔案,在loadClass方法中用到,所以我們只能重寫這個方法了,只要在這個方法中找到class檔案,再將它用defineClass方法返回一個Class物件即可。defineClass這個方法很簡單就是將class檔案的位元組陣列程式設計一個class物件,這個方法肯定不能重寫,內部實現是在C/C++程式碼中實現的
2、自定義類載入器實現
1)首先,定義需要載入的一個類:ClassLoaderAttachment.java,編譯成ClassLoaderAttachment.class檔案,放到工程目錄下。
2)定義自定義類載入器
3)測試類:
輸出結果:
note:
因為loadClass方法在使用系統類載入器AppClassLoader的時候需要傳遞全稱(包括包名),我們傳遞ClassLoaderAttachment的話,AppClassLoader也是沒有找到這個ClassLoaderAttachment,所以還是MyClassLoader處理了。
如果改成:
結果:
例子中class檔案可以加密,具體可參考文章:
http://www.wjdiankong.cn/java高新技術第一篇:類載入器詳解/