JavaTM安全体系结构(JDK1.2)
5. 安全类装载
动态类装载是Java虚拟机的一个重要特性,因为它为Java平台提供了一种在运行时安装软件的能力。它有许多独特的性质。首先,惰性装载表示按需求并在可能的最后一刻装载类;第二,通过增加链接时检查(它代替了某些运行时检查,并仅执行一次),动态类装载维护了Java虚拟机的类型安全;再有,程序员可定义他们自己的类装载器。例如,指定某些的远程位置,类装载器从哪里装载某些类,或为哪些类分配适当的安全属性等。最后,类装载器可为各种软件部件提供单独的命名空间。例如,一个浏览器可使用单独的类装载器从不同的web页装载Applets,这就维护了在那些Applet类之间的一定程度的隔离。事实上,这些类可包含名称相同的类──这些类被Java虚拟机当作截然不同的类型。
类装载机制不仅是Java编程语言的重要动态特性,而且在保证安全方面也起到了关键的作用。原因是类装载器负责类文件的定位和提取、安全策略的查询以及用适当的许可定义类对象等任务。
5.1 类装载器类层次
当装载一个类时,因为在一个Java虚拟机中可能有多个类装载器实例,所以一个重要的问题是,如何确定使用哪个类装载器。JDK1.2引进了具有独特性能的多重类装载器类,于是,另一个重要的问题就是,我们应该使用哪种类型的类装载器。
类装载器类层次的根是一个被称为java.lang.ClassLoader的抽象类,它最初是在JDK1.0中被定义的,并在此之后,又做了进一步的扩展。类java.security.SecureClassLoader是在JDK1.2中引进的,它是这个抽象的ClassLoader类的子类和一个具体的实现。类java.net.URLClassLoader是SecureClassLoader的一个子类。
一个被称作appletviewer的实用程序使用私有类sun.applet.AppletClassLoader来装载Applets。在JDK1.0中,AppletClassLoader是ClassLoader的一个子类和一个具体实现。在JDK1.2中,它是URLClassLoader的一个子类。
当创建一个用户定制的类装载器类时,你可以从任何以上类装载器类中创建子类,这依赖于用户类装载器的特殊需求。因为AppletClassLoader是一个在sun.*包中定义的专用类,它不被支持并可能被更改,因而,不应该由它创建子类。
5.2 原始类装载器
因为每个类都是由它的类装载器所装载的,并且每个类装载器本身是一个类,它必须由另外一个类装载器来装载,我们似乎遇到了明显的鸡和蛋的问题。也就是说第一个类装载器从何而来?一个"原始的"类装载器解开了这个类装载的难题。原始类装载器一般用本机语言编写(如C语言),并且在Java上下文中不表明它自己。原始类装载器经常从本地文件系统用依赖于平台的方式装载类。
某些类,如:那些在Java.*包中定义的类,对完成Java虚拟机和运行时系统的功能是十分重要的,它们经常被引用为基类。由于历史上的原因,所有这样的类都有一个空值类装载器,这个空值类装载器或许是一个原始类装载器存在的唯一标记。事实上直接将空值类装载器当作原始类装载器看待则容易的多。
如果给出在一个Java应用环境中的所有类,则我们可以轻易地形成一个类装载树,以反映类装载之间的关系,每个不是类装载器的类是一个叶子节点,每个类的父节点是它的类装载器,空值类装载器则是根类。因为不可能有循环所以这样的结构是一个树-一个类装载器不可能装载它的祖先类装载器,
5.3 类装载器授权
当一个类装载器被要求装载一个类时,这个类装载器可以自己装载这个类,也可以要求其它的类装载器来装载这个类。换言之,第一个类装载器可授权给第二个类装载器,授权关系在一定意义上是虚拟的,它与哪个类装载器装载哪个其它类装载器无关。当类装载器对象被创建时,则授权关系被形成(并且是以父子关系的形式)。然而,系统类装载器是所有类装载器授权根祖先。必须注意保证这种授权关系不包括循环,否则,该授权过程可能进入死循环。
5.4 类解析算法
JDK 1.2 ClassLoader的方法装载一个类时的缺省实现,以如下顺序搜索类
检查该类是否已经被装载。
如果当前类装载器有一个指定的授权父辈,授权给这个父辈来装载这个类,如果没有父辈,则授权给原始类装载器。
调用一个能够用户化的方法,以搜索其它地方的类。
这里的第一步是为了查询类装载器的本地缓存(或它的功能等价物,如全局缓存),以确认一个要装载的类是否与目标类相匹配。最后一步提供了一种使寻找类的机制用户化的途径。这样,用户类装载器可覆盖这个方法来指明一个类应该如何被查询。例如一个Applet类装载器可覆盖这个方法以回到Applet的源主机,通过网络装载该类。
如果在任意步骤中,找到该类,它就被返回;如果使用上述步骤未发现类,则一个异常ClassNotFound被扔出。
类型安全是十分重要的,相同的类只能由相同的类装载器最多装载一次。如果这个类不是那些已装载的类之一,当前类装载器则试图将这个任务授权给父辈类装载器。这个情况可递推地发生。它可以保证使用适当类装载器。例如,当装载一个系统类时,在到达系统类装载器之前,授权过程将一直递推地进行。
我们已在早些时候知道了授权算法。但是,假设给定任意一个类的名称,我们应从哪个类装载器开始,来装载这个类呢?有关确定类装载器的规则如下:
当装载一个应用程序的第一个类时,使用URLClassLoader的一个新实例;
当装载一个Applet的第一个类时,使用AppletClassLoader的一个新实例;
当java.lang.ClassForName被直接调用时,使用原始类装载器;
当装载一个类的请求被现存类中对这个类的引用所触发时,使用现存类的类装载器来装载这个类。
请注意:有关使用URLClassLoader和AppletClassLoader实例的规则有一些例外,并根据特定的系统环境而有所变化。例如,一个web浏览器可能会选择再次使用一个现存的AppletClassLoader来从相同的web页中装载Applet类。
由于类装载器的能力极大,所以我们严格地限制由谁来创建类装载器实例。另一方面,我们期望能为应用程序或Applets提供一种简单的机制,以指明URL地址并从这些地方装载类。我们可提供静态方法以使各种应用程序能创建URLClassLoader类的实例,但没有其它装载器类型。
..........|Next|..........
欢迎与我们联系:webmaster@prc.sun.com
版权所有 1997-1998 Sun(中国)公司,北京南礼士路66号建威大厦16层
All rights reserved.Legal Terms