雙親委派模型

http://blog.csdn.net/p10010/article/details/50448491


說道雙親委派模型,就要從類加載器說起。。。。。。。。。。。


Java虛擬機類加載過程是把Class類文件加載到內存,並對Class文件中的數據進行校驗、轉換解析和初始化,最終形成可以被虛擬機直接使用的java類型的過程。

在加載階段,java虛擬機需要完成以下3件事:

a.通過一個類的全限定名來獲取定義此類的二進制字節流。

b.將定義類的二進制字節流所代表的靜態存儲結構轉換爲方法區的運行時數據結構

c.在java堆中生成一個代表該類的java.lang.Class對象,作爲方法區數據的訪問入口。

而類的加載過程是通過類加載器完成的。


在Java中,任意一個類都需要由加載它的類加載器和這個類本身一同確定其在java虛擬機中的唯一性,即比較兩個類是否相等,只有在這兩個類是由同一個類加載器加載的前提之下才有意義,否則,即使這兩個類來源於同一個Class類文件,只要加載它的類加載器不相同,那麼這兩個類必定不相等(這裏的相等包括代表類的Class對象的equals()方法、isAssignableFrom()方法、isInstance()方法和instanceof關鍵字的結果)。

看下面的例子:

[java] view plain copy

  1. package com.test;    

  2.     

  3. public class ClassLoaderTest {    

  4.     public static void main(String[] args)throws Exception{    

  5.         //匿名內部類實現自定義類加載器    

  6.     ClassLoader myClassLoader = new ClassLoader(){    

  7.     protected Class<?> findClass(String name)throws ClassNotFoundException{    

  8.         //獲取類文件名    

  9.     String filename = name.substring(name.lastIndexOf(“.”) + 1) + “.class”;    

  10.     InputStream in = getClass().getResourceAsStream(filename);    

  11.     if(in == null){    

  12.     throw RuntimeException(“Could not found class file:” + filename);    

  13. }    

  14. byte[] b = new byte[in.available()];    

  15. return defineClass(name, b, 0, b.length);    

  16. }catch(IOException e){    

  17.     throw new ClassNotFoundException(name);    

  18. }    

  19. };    

  20. Object obj = myClassLoader.loadClass(“com.test.ClassLoaderTest”).newInstance();    

  21. System.out.println(obj.getClass());    

  22. System.out.println(obj instanceof com.test. ClassLoaderTest);    

  23. }    

  24. }    



輸出結果如下:

com.test.ClassLoaderTest

false

之所以instanceof會返回false,是因爲com.test.ClassLoaderTest類默認使用Application ClassLoader加載,而obj是通過自定義類加載器加載的,類加載不相同,因此不相等。


說到這裏就輪到雙親委派模型出場了。

先看雙親委派模型的經典體系統:


做一個簡單解釋:

(1).BootStrap ClassLoader:啓動類加載器,負責加載存放在%JAVA_HOME%\lib目錄中的,或者通被-Xbootclasspath參數所指定的路徑中的,並且被java虛擬機識別的(僅按照文件名識別,如rt.jar,名字不符合的類庫,即使放在指定路徑中也不會被加載)類庫到虛擬機的內存中,啓動類加載器無法被java程序直接引用。

(2).Extension ClassLoader:擴展類加載器,由sun.misc.Launcher$ExtClassLoader實現,負責加載%JAVA_HOME%\lib\ext目錄中的,或者被java.ext.dirs系統變量所指定的路徑中的所有類庫,開發者可以直接使用擴展類加載器。

(3).Application ClassLoader:應用程序類加載器,由sun.misc.Launcher$AppClassLoader實現,負責加載用戶類路徑classpath上所指定的類庫,是類加載器ClassLoader中的getSystemClassLoader()方法的返回值,開發者可以直接使用應用程序類加載器,如果程序中沒有自定義過類加載器,該加載器就是程序中默認的類加載器。


這裏需要注意的是上述三個JDK提供的類加載器雖然是父子類加載器關係,但是沒有使用繼承,而是使用了組合關係。

從JDK1.2開始,java虛擬機規範推薦開發者使用雙親委派模式(ParentsDelegation Model)進行類加載,其加載過程如下:

(1).如果一個類加載器收到了類加載請求,它首先不會自己去嘗試加載這個類,而是把類加載請求委派給父類加載器去完成。

(2).每一層的類加載器都把類加載請求委派給父類加載器,直到所有的類加載請求都應該傳遞給頂層的啓動類加載器。

(3).如果頂層的啓動類加載器無法完成加載請求,子類加載器嘗試去加載,如果連最初發起類加載請求的類加載器也無法完成加載請求時,將會拋出ClassNotFoundException,而不再調用其子類加載器去進行類加載。

雙親委派 模式的類加載機制的優點是java類它的類加載器一起具備了一種帶優先級的層次關係,越是基礎的類,越是被上層的類加載器進行加載,保證了java程序的穩定運行。雙親委派模式的實現:

[java] view plain copy

  1. <span style="color:#333333;">protected synchronized Class<?> loadClass(String name, Boolean resolve) throws ClassNotFoundException{    

  2.     //首先檢查請求的類是否已經被加載過    

  3.     Class c = findLoadedClass(name);    

  4.     if(c == null){    

  5.     try{    

  6.         if(parent != null){//委派父類加載器加載    

  7.     c = parent.loadClass(name, false);    

  8. }    

  9. else{//委派啓動類加載器加載    

  10.     c = findBootstrapClassOrNull(name);     

  11. }    

  12. }catch(ClassNotFoundException e){    

  13.     //父類加載器無法完成類加載請求    

  14. }    

  15. if(c == null){//本身類加載器進行類加載    

  16.     c = findClass(name);    

  17. }    

  18. }    

  19. if(resolve){    

  20.     resolveClass(c);    

  21. }    

  22. return c;    

  23. }  </span>  


通過雙親委派模型我們就能很好解決文章開始我們自定義的類加載器所出現的問題。


這裏需要注意的是在JDK1.2之前,類加載尚未引入雙親委派模式,因此實現自定義類加載器時常常重寫loadClass方法,提供雙親委派邏輯,從JDK1.2之後,雙親委派模式已經被引入到類加載體系中,自定義類加載器時不需要在自己寫雙親委派的邏輯,因此不鼓勵重寫loadClass方法,而推薦重寫findClass方法。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章