| |
Java程序类加载完全揭密 |
|
时间: 2005-10-19 来自:matrix |
 |
|
|
类加载器如何工作?
除了引导类加载器,所有的类加载器都有一个父类加载器,不仅如此,所有的类加载器也都是java.lang.ClassLoader类型。以上两种类加载器是不同的,而且对于开发者自订制的类加载器的正常运行也至关重要。最重要的方面是正确设置父类加载器。任何类加载器,其父类加载器是加载该类加载器的类加载器实例。(记住,类加载器本身也是一个类!)
使用loadClass()方法可以从类加载器中获得该类。我们可以通过java.lang.ClassLoader的源代码来了解该方法工作的细节,如下:
我们可以使用ClassLoader的两种构造方法来设置父类加载器:
public class MyClassLoader extends ClassLoader { public MyClassLoader() { super(MyClassLoader.class.getClassLoader()); } } | 或
public class MyClassLoader extends ClassLoader { public MyClassLoader() { super(getClass().getClassLoader()); } } | 第一种方式较为常用,因为通常不建议在构造方法里调用getClass()方法,因为对象的初始化只是在构造方法的出口处才完全完成。因此,如果父类加载器被正确建立,当要示从一个类加载器的实例获得一个类时,如果它不能找到这个类,它应该首先去访问其父类。如果父类不能找到它(即其父类也不能找不这个类,等等),而且如果findBootstrapClass0()方法也失败了,则调用findClass()方法。findClass()方法的缺省实现会抛出ClassNotFoundException,当它们继承java.lang.ClassLoader来订制类加载器时开发者需要实现这个方法。findClass()的缺省实现方式如下:
| protected Class<?> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name); } | 在findClass()方法内部,类加载器需要获取任意来源的字节码。来源可以是文件系统,URL,数据库,可以产生字节码的另一个应用程序,及其他类似的可以产生java规范的字节码的来源。你甚至可以使用BCEL (Byte Code Engineering Library:字节码工程库),它提供了运行时创建类的捷径。BCEL已经被成功地使用在以下方面:编译器,优化器,混淆器,代码产生器及其他分析工具。一旦字节码被检索,此方法就会调用defineClass()方法,此行为对不同的类加载实例是有差异的。因此,如果两个类加载实例从同一个来源定义一个类,所定义的结果是不同的。
JAVA语言规范(Java language specification)详细解释了JAVA执行引擎中的类或接口的加载(loading),链接(linking)或初始化(initialization)过程。
图一显示了一个主类称为MyMainClass的应用程序。依照之前的阐述,MyMainClass.class会被AppClassLoader加载。 MyMainClass创建了两个类加载器的实例:CustomClassLoader1 和 CustomClassLoader2,他们可以从某数据源(比如网络)获取名为Target的字节码。这表示类Target的类定义不在应用程序类路径或扩展类路径。在这种情况下,如果MyMainClass想要用自定义的类加载器加载Target类,CustomClassLoader1和CustomClassLoader2会分别独立地加载并定义Target.class类。这在java中有重要的意义。如果Target类有一些静态的初始化代码,并且假设我们只希望这些代码在JVM中只执行一次,而这些代码在我们目前的步骤中会执行两次——分别被不同的CustomClassLoaders加载并执行。如果类Target被两个CustomClassLoaders加载并创建两个实例Target1和Target2,如图一显示,它们不是类型兼容的。换句话说,在JVM中无法执行以下代码:
| Target target3 = (Target) target2; | 以上代码会抛出一个ClassCastException。这是因为JVM把他们视为分别不同的类,因为他们被不同的类加载器所定义。这种情况当我们不是使用两个不同的类加载器CustomClassLoader1 和 CustomClassLoader2,而是使用同一个类加载器CustomClassLoader的不同实例时,也会出现同样的错误。这些会在本文后边用具体代码说明。
 图1. 在同一个JVM中多个类加载器加载同一个目标类 |
|
|
|
|
|
|
|
|