众所周知,Java 2之后在ClassLoader中使用了parent-Delegation模式,目的是为了简化User-defined ClassLoader的实现和更好的安全性。
ClassLoader通常作为Java 安全性的第一道屏障,
- 它会阻止恶意代码对原有可信任代码的干扰。
- 保护可信任代码。
- 将不同的代码分类(称之为protection domains 或 runtime domain)。
ClassLoader会在运行时将每一个加载过的class分配到一个唯一命名空间([i]name-space[/i])之下。不同的class根据加载的class loader的不同,被分配到不同的name-space。JVM会为每一个class loader维护一个唯一的name-space名称。一旦一个class A 已经被加载并且被安置在name-space N下,就不可能在加载另一个A 在同一个name-space下。如果强制这么做(通过user-defined class loader),会得到一个
LinkageError(duplicate class definition:[your class name])。有时这个name-space也称为[i]runtime package[/i] ,Java语言中的包访问成员(friendly)实际上指的是运行时包访问可见,而不是编译时。因此当你试图访问不在同一个runtime package的成员是(即便在编译时它们在同一个包内,但是却由不同的class loader加载)也同样会得到
java.lang.IllegalAccessException: Class A can not access a member of class B with modifiers "" 这样的异常。
一个User-defined必须依赖其他的Class loader,至少需要system class loader,来协助它完成对某些class的加载工作。在1.2之后,每一个class loader除了bootstrap class loader都有一个parent class loader。每一次需要加载class时,首先会去请求parent class loader来加载这个class,如果不成功才会自己进行加载工作。这称为parent-delegation model。
如果你违反了这一协定的话,通常你会得到一个
NoClassDefFoundError。因为你的class Loader无法找到一些Java API中的类 ,比如说java.lang.Object。
你可能想如果将这些Java API中的类也放在你的class loader的路径下,是否就可以了呢?JVM不会允许你这样做的。你会得到:
java.lang.SecurityException: Prohibited package name: java.lang,这样的异常。在Java 1.2之后,所有的java core api都由一个JVM内置的class loader加载,并且java 安全机制不允许这些类或接口被除此之外的class loader加载。
在一个缺省的JVM环境下,通常存在两个Class Loader。一个就是所谓的bootstrap class loader,它用来加载所有的java core api(包括所有java包下的类),另一个是系统class loader,它用来加载你定义的class_path下的类。
通常使用Class.getClassLoader()方法可以查询到加载这个class的class loader的信息。但是对于sun 的 jvm 实现而言,对于core api的class这样做只会得到null。(见 java doc)。
Ps: 系统class loader为sun.misc.Launcher$AppClassLoader。
原文地址:http://www.chinaitpower.com/A200507/2005-07-24/165821.html