ITEEDU

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。