我们知道,Java利用ClassLoader将类载入内存,并且在同一应用中,可以有很多个ClassLoader,通过委派机制,把装载的任务传递给
上级的装载器的,依次类推,直到启动类装载器(没有上级类装载器)。如果启动类装载器能够装载这个类,那么它会首先装载。如果不能,则往下传递。当父类为
null时,JVM内置的类(称为:bootstrap class
loader)就会充当父类。想想眼下的越来越多用XML文件做配置文件或者是描述符、部署符。其实这些通过XML文档描述的配置信息最终都要变成
Java类,基实都是通过ClassLoader来完成的。URLClassLoader是ClassLoader的子类,它用于从指向 JAR
文件和目录的 URL 的搜索路径加载类和资源。也就是说,通过URLClassLoader就可以加载指定jar中的class到内存中。 下面来看一个例子,在该例子中,我们要完成的工作是利用URLClassLoader加载jar并运行其中的类的某个方法。 首先我们定义一个接口,使所有继承它的类都必须实现action方法,如下: public interface ActionInterface { 接下来新建一工程,为了编译通过,引入之前打好的testInterface.jar包。并创建TestAction类,使它实现ActionInterface接口。如下:
新建一工程,引入testInterface.jar包。并创建一可执行类(main方法),在其中加入如下代码: URL url = new URL(“file:C: / test.jar”); 执行程序后,在控制台上如期打印出我们想要的内容。但是,事情并没有那么简单,当我们将该代码移动web应用中时,就会抛出异常。原来,Java为我们提供了三种可选择的ClassLoader: 在上例中我们使用javac命令来运行该程序,这时候使用的是系统类加载器 (system classloader)。这个类加载器处理 -classpath下的类加载工作,可以通过ClassLoader.getSystemClassLoader()方法调用。 ClassLoader 下所有的 getSystemXXX()的静态方法都是通过这个方法定义的。在代码中,应该尽量少地调用这个方法,以其它的类加载器作为代理。否则代码将只能工作在 简单的命令行应用中。当在web应用中时,服务器也是利用ClassLoader来加载class的,由于ClassLoader的不同,所以在强制转型 时JVM认定不是同一类型。(在JAVA中,一个类用其完全匹配类名(fully qualified class name)作为标识,这里指的完全匹配类名包括包名和类名。但在JVM中一个类用其全名和一个加载类ClassLoader的实例作为唯一标识。因此,如 果一个名为Pg的包中,有一个名为Cl的类,被类加载器KlassLoader的一个实例kl1加载,Cl的实例,即C1.class在JVM中表示为 (Cl, Pg, kl1)。这意味着两个类加载器的实例(Cl, Pg, kl1) 和 (Cl, Pg, kl2)是不同的,被它们所加载的类也因此完全不同,互不兼容的。)为了能够使程序正确运行,我们首要解决的问题就是,如何将 URLClassLoader加载的类,同当前ClassLoader保持在同一类加载器中。解决方法很简单,利用java提供的第三种 ClassLoader—当前线程类加载器即可。jdk api文档就会发现,URLClassLoader提供了三种构造方式: // 使用默认的委托父 ClassLoader 为指定的 URL 构造一个新 URLClassLoader。 URLClassLoader myClassLoader = new URLClassLoader( new URL[] { url } , Thread.currentThread().getContextClassLoader()); |
|