深入類載入器(三)----類載入器的分類和等級
深入類載入器階層(三種類載入器)代理載入模式,雙親委託機制
我們首先要知道在java中,類載入器也是分等級的。最進階的一種載入器是載入java中的核心包下的類。比如說java.ang.String類就是通過這種類載入器進行載入的。下一個等級的就是額外的類載入器。也是載入一些類的。再下一級的就是應用程式的類載入器。再下一級的就是自訂的類載入器了。但是這幾種載入器之間不是繼承關係的,而是組合關係的。這是要注意的。
在java中,類載入採用的是代理模式。所謂的代理模式,可以簡單的理解為,看起來是這個類載入器進行載入,但其實並不是這個載入器進行載入。這就是代理模式。
在代理模式中,有一個比較重要的一種是雙親委託模式。所謂的雙親委託模式就是:比如說,我定義了一個類A,在載入類A的時候,首先由自訂的類載入器,再到應用程式的類載入器,再到拓展的類載入器,最後到最進階的載入器。首先是由最進階的載入器進行判斷,它是否能夠載入這個類,如果能夠載入的話,就進行載入。如果不能夠進行載入的話,再接下來看一下額外的類載入器能否進行載入。這樣一層一層地往下。如果都不能載入的話,那麼就會出現錯誤。這是要注意的。
雙親委託機制的最大的好處就是可以確保是安全的。
比如說,我舉一個例子:
我首先定義可java.lang包。然後我在這個package的下面定義了一個String類。由於String類是java中的核心包,理應是由最高等級的那個類載入器進行載入的。我們採用了雙親委託的模式: 由上往下,一層一層進行判斷,是否能夠載入。首先是在最高等級的那個類載入器當中,發現String類是核心包下的一個類。那麼就不會對我們自訂的一個類進行載入了。所以即使我們定義了那個類,我們也不能使用這個類。這就是雙親委託模式的好處,可以確保了安全。但是也並不是所有的類載入的過程都是採用雙親委託模式的。比如Tomcat伺服器採用的就不是雙親委託模式,它的載入的過程和雙親委託模式是正好相反的。但是也是代理的模式。
package com.lg.test;
public class Demo02 {
public static void main(String[] args){
System.out.println(ClassLoader.getSystemClassLoader());
System.out.println(ClassLoader.getSystemClassLoader().getParent());
//為什麼最後一個類載入器顯示的是null呢。其實也是很容易理解的。
//由於這個最高等級的類載入器是使用原始代碼進行載入的。也就是實用c++或者c進行編寫的。
//所以在java中載入不出來。
System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent());
//這裡顯示的是類載入的路徑。由於bin目錄下放置的都是一些類的編譯成的class檔案。所以
//會從這裡進行載入。這是要注意的。
System.out.println(System.getProperty("java.class.path"));
String info="liguo";
//通過這個我們發現,我們定義的java.lang.String下的包並沒有被使用
//並且我們發現類載入器是null。那麼通過代理模式下的雙親委託模式,我們就可以保證類載入的
//安全性。這是要注意的。
System.out.println(info.toString());
System.out.println(info.getClass().getClassLoader());
}
}
最後的輸出的結果為:
sun.misc.Launcher$AppClassLoader@4e0e2f2a
sun.misc.Launcher$ExtClassLoader@2a139a55
null
C:\Users\liguo\workspace\Others\bin
liguo
null