From Gossip@Openhome

Java Gossip: 自訂 ClassLoader

ExtClassLoader與AppClassLoader都是 java.net.URLClassLoader的子類別,您可以在使用java啟動程式時,使用以下的指令來指定ExtClassLoader的搜尋路徑:
java -Djava.ext.dirs=c:\workspace\ YourClass
 
可以在使用java啟動程式時,使用-classpath或-cp來指定AppClassLoader的搜尋路徑,也就是設定Classpath:
java -classpath c:\workspace\ YourClass
 
ExtClassLoader與AppClassLoader在程式啟動後會在虛擬機器中存在一份,您在程式運行過程中就無法再改變它的搜尋路徑,如果在程式運行過程中,打算動態決定從其它的路徑載入類別,就要產生新的類別載入器。

您可以使用URLClassLoader來產生新的類別載入器,它需要java.net.URL作為其參數來指定類別載入的搜尋路徑,例如:
URL url1 = new URL("file:/d:/workspace/");
URLClassLoader urlClassLoader1 =
                    new URLClassLoader(new URL[] {url1});
Class c1 = urlClassLoader1.loadClass("ClassDemoTest");
 

在新增了ClassLoader後,您可以使用它的loadClass()方法來指定要載入的類別名稱,新增 ClassLoader時,會自動將新增的ClassLoader的parent設定為AppClassLoader,並在每次載入類別時,先委託 parent代為搜尋,所以上例中搜尋ClassDemoTest類別時,會一路往上委託至Bootstrap Loader先開始搜尋,接著是ExtClassLoader、AppClassLoader,如果都找不到,才使用新增的ClassLoader搜尋。

由同一個ClassLoader載入的類別檔案,會只有一份Class實例,如果同一個類別檔案是由兩個不同的ClassLoader載入,則會有兩份不 同的Class實例,注意這個說法,如果有兩個不同的ClassLoader搜尋同一個類別,如果在parent的 AppClassLoader搜尋路徑中就可以找到,則Class實例就只會有一個,如果是由各自的ClassLoader搜尋到,則Class的實例會 有兩份。

下面這個實例是個簡單的示範,其中"file:/d:/workspace/"不在ExtClassLoader或AppClassLoader的搜尋路徑中,所以同一個類別會分由兩個ClassLoader載入,因而會有兩份Class實例:

  • ClassLoaderDemo.java
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

public class ClassLoaderDemo {
public static void main(String[] args)
throws MalformedURLException,
ClassNotFoundException {
URL url1 = new URL("file:/d:/workspace/");
URLClassLoader urlClassLoader1 =
new URLClassLoader(new URL[] {url1});
Class c1 =
urlClassLoader1.loadClass("ClassLoaderTest");

System.out.println(c1);

URL url2 = new URL("file:/d:/workspace/");
URLClassLoader urlClassLoader2 =
new URLClassLoader(new URL[] {url2});
Class c2 =
urlClassLoader2.loadClass("ClassLoaderTest");

System.out.println(c2);

System.out.println(c1 == c2);
}
}

執行結果會顯示false;如果將ClassLoaderTest移至Classpath下,也就是 AppClassLoader可以搜尋到的路徑下,結果是ClassLoaderTest會被AppClassLoader載入,即使我們使用兩個自訂的 ClassLoader,但載入的Class實例也只有一個,再次執行同一個程式,則結果會顯示true。