2012-03-14 70 views
2

我有兩個類如下如何以及當Bootstrap jar找到../ lib/rt.jar和../lib/ext.**jar時被加載?

package foo; 
import java.io.File; 
import java.io.IOException; 
import java.io.InputStream; 

public class CustomClassLoader extends ClassLoader { 
    public CustomClassLoader(ClassLoader parent){ 
     super(parent); 
    } 

    public Class<?> loadClass(String name) throws ClassNotFoundException { 
     System.out.println(" >>> loading " + name); 

     if (name.startsWith("foo")) { 
      return getClass(name); 
     } 
     return super.loadClass(name); 
    } 

    public Class getClass(String name){ 
     try { 
      byte[] data= getClassByteData(name); 
      return this.defineClass(name, data, 0, data.length); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 

    public byte[] getClassByteData(String name) throws IOException { 
     String file = name.replace(".", File.separator)+".class"; 
     InputStream in = this.getClass().getResourceAsStream("/"+file); 
     int length = in.available(); 
     byte[] datas = new byte[length]; 
     in.read(datas, 0, length); 
     return datas; 
    } 
} 


package foo; 

public class Test { 
    public static void main(String[] args) { 
     System.out.println(" Who is my loader? >>" + Test.class.getClassLoader()); 
    } 

} 

運行:java -Djava.system.class.loader=foo.CustomClassLoader foo.Test

輸出:

>>> loading java.lang.System 
>>> loading java.nio.charset.Charset 
>>> loading java.lang.String 
>>> loading foo.Test 
>>> loading java.lang.Object 
>>> loading java.lang.StringBuilder 
>>> loading java.lang.Class 
>>> loading java.io.PrintStream 
Who is my loader? >>[email protected] 

我的問題是如下:

  1. 爲什麼那些java.lang.Systemjava.nio.charset.Charset等如前所述ve會被加載CustomClassLoader?在我的想法中,當我運行java -Djava.system.class.loader foo.Test時,JVM首先搜索類foo.Test,加載它,執行主要方法,然後當它檢測到System.out.println()時,它將繼續加載類java.lang.Systemjava.io.PrintWriter,因爲這些類是由它使用的, ?

  2. 當我運行它使用位於java.lang包中的一些類的類,這些類也將被再次加載,在我的情況下放CustomClassLoader >> >>的ExtClassLoader BoostrapClassLoader加載?

  3. /lib/rt.jar/lib/ext/**.jar被加載時,在我們運行一個像java foo.Test這樣的類之前,所有這些類都已經加載了bean?

非常感謝您的幫助!

回答

3

要回答你的問題,讓我們依次進行。

  1. Java的ClassLoading機制基於委託模型,其中試圖加載類通常首先被委派給父類加載器。如果父類加載器能夠成功加載該類,則加載的類將傳回代理鏈,並由最初調用的任何類加載器返回。由於您將自定義類加載器設置爲系統類加載器,因此JVM將其實例化爲應用程序啓動時使用的默認加載器。然後用它來加載它需要的所有類。大多數這些類(即任何不以foo開頭的東西。*)委託給父類加載器,這就解釋了爲什麼你會看到關於你的類加載器嘗試加載它們的消息。

  2. 由於將非foo。*類的加載委託給父類加載器,因此再次加載系統類(如System.out)將由父類加載器處理,該類加載器處理緩存所有加載的類和將返回先前加載的實例。

  3. 加載rt.jar和lib/ext/*。jar文件由父類加載器(或其父代)處理,而不是您。因此,您的類加載器不需要關注這些JAR文件。

通常,構建自定義類加載器是爲了確保可以從非標準位置(例如存儲在數據庫中的JAR)加載類。

2

我假設你運行的實際命令行是java -Djava.system.class.loader=foo.CustomClassLoader foo.Test

  1. 一般來說,所有的類都可以被不同的類加載器多次加載。事實上,他們甚至被認爲是不同的班級。那麼foo.Test需要一個java.lang.System,它的類加載器被調用來查找或加載它。

  2. 在你的情況下,CustomClassLoader將非foo類的加載委託給super,它不會再次加載同一個類,但返回以前加載的類。

  3. 談論加載罐子誤導。來自這些罐子的類別按需加載。爲了加載任何程序,JVM需要創建一個線程,所以Thread類和它的依賴關係在你的類之前加載。

您可以使用-verbose:class運行sun的java來查看類是如何加載的。

相關問題