读书人

java类装载器详细引见

发布时间: 2012-10-25 10:58:58 作者: rapoo

java类装载器详细介绍


java类装载器详细引见

?

Java类装载器子系统

?

?? ? ? ? 在Java虚拟机中,负责查找并装载类型的那部分被称为类装载子系统。上图描述了,类装载器在JVM组成中的位置。

?? ? ? ? Java虚拟机有两种类装载器:启动类装载器和用户自定义类装载器。前者是Java虚拟机实现的一部分,后者则是Java程序的一部分。由不同的类装载器装载的类将被放在虚拟机内部的不同命名空间中。

?

?? ? ? ? 类装载器子系统涉及Java虚拟机的其他几个组成部分,以及几个来自java.lang库的类。比如,用户自定义的类装载器是普通的Java对象,他的类必须派生自java.lang.ClassLoader类。ClassLoader中定义的方法为程序提供了访问类装载器机制的借口。此外,对于每一个被装载的类型,Java虚拟机都会为它创建一个java.lang.Class类的实例来代表该类型。和其他所有对象一样,用户自定义的类装载器以及Class类的实例都放在内存中的堆区,而装载的类型信息则都位于方法区。

?

?? ? ? ? ?装载、连接以及初始化

?

?? ? ? ? ?类装载器子系统出来要定位和导入二进制class文件外,还必须负责验证被导入类的正确性,为类变量分配并初始化内存,以及帮助解析符号引用。这些动作必须严格按以下顺序进行:1)装载(Load)-------查找并装载类型的二进制数据

?? ? ?2)连接(Link)-------执行验证,准备,以及解析(可选)。

?? ? ? ? ? 验证(Verify) ? 确保被导入类型的正确性

?? ? ? ? ? 准备(Prepare) ? 为类变量分配内存,并将其初始化为默认值

?? ? ? ? ? 解析(Resolve) ? 把类型中的符号引用转换为直接引用

?? ? ?3)初始化(Initialize)------把类变量初始化为正确初始值? ??

?

?? ? ? ? ? 启动类装载器

?

?? ? ? ? ? 只要符合Java class文件格式的二进制文件,Java虚拟机实现都必须能够从中辨别并装载其中的类和接口。某些 ?虚拟机实现也可以识别其他的非规范的二进制格式文件,但它必须能够辨别class文件。

?? ? ? ? ? 每个java虚拟机实现都必须有一个启动类装载器,它知道怎么装载受信任的类,比如java api的class文件。Java虚拟机规范并未规定启动类装载器如何去寻找class文件,这又是一件保留给具体的实现设计者去决定的事情。

?? ? ? ? ? 只要给定某个类型的全限定名,启动类装载器就必须能够以某种方式得到定义该类型的数据。比如,在Window 98平台上,Sun的JDK 1.1是这样工作的:首先它逐个搜索用户在CLASSPATH环境变量中定义的目录,直到找到一个名为”该类型名+.class“的文件为止。除非该类型属于某个未命名的包,否则启动类装载器会在CLASSPATH包含的目录的子目录中寻找这样一个文件,这些子目录的路径名是根据类型的包名称构建的。比如,如果启动类装载器正在搜索这样一个类:java.lang.Object,那么它将在每一个CLASSPATH包含的目录下,查找java\lang这样的一个字目录,以及其中的Object.class文件。

?? ? ? ? ? ?在Sun的JDK 1.2中,与1.1版本不同,启动类装载器将只在系统类(java api的类文件)的安装路径中查找要装入的类;而搜索CLASSPATH目录的任务,现在交给了系统类装载器-----它是一个自定义的类装载器,当虚拟机启动时就被自动创建。

?

?

?? ? ? ? ? ?用户自定义类装载器

?

?? ? ? ? ? ?尽管”用户自定义类装载器“本身是java程序的一部分,但类ClassLoader中的四个方法时通往Java虚拟机的通道:

?? ? ? ? ? 上图是Java类装载器的体系结构。

?? 由于Java虚拟机采用这种方式进行类的装载,所以被装载的类默认情况下只能看到被同一个类装载器装载的别的类。通过这种方法,Java的体系结构允许在一个Java应用程序中建立多个命名空间。运行时的Java程序中的每个类装载器都有一个他自己的命名空间。

?? ? ? ? ? 一个Java应用程序能够从同一个类或者多个类中实例化多个用户定义的类装载器。因此,需要多少个(或者多少种)用户自定义的类装载器,java应用程序就可以创建多少个(或多少种),被不同的类装载器装载的类存放在不同的命名空间中,他们不能互相访问,除非应用程序显示地允许这样做。当编写一个Java应用程序的时候,从不同源文件装载的类可以分割在不同的命名空间中。通过这种方法,就能够使用Java类装载器的体系结构来控制从不同源文件中装载的代码之间的相互影响,特别是能够阻止恶意代码获取访问和破坏善意代码的权限,可以看出Java类装载器的体系结构提供了对网络移动性的支持。

?? Web浏览器是一个动态扩展的例子,Web浏览器使用用户自定义的类装载器从网络上下载用于Java applet的class文件。web浏览器使用一个用来安装用户自定义类装载器的Java应用程序,这个用户定义的类装载器通常被称为Java applet类装载器,他知道如何向Http服务器请求class文件。Java applet可以作为动态扩展的例子,因为当浏览器遇到有Java applet的页面的时候,才决定是否需要下载class文件。

?? ? ? ? ? Web浏览器启动的Java应用程序通常为每个提供class文件的网络地址分步创建不同的用户自定义类装载器,因此,不同的用户自定义类装载器庄子不同来源的class文件。这就可以吧他们分别放置在Java主机应用程序的不同命名空间之中。由于不同来源的Java applet代码不会直接妨碍到从别的地方下载的class文件。

?

?? ?2.JVM运行时的ClassLoader介绍

?

JVM在运行时会产生三个ClassLoader:Bootstrap ClassLoader、Extension ClassLoader和AppClassLoader.其中,Bootstrap是用C++编写的,我们在Java中看不到它,是null。它用来加载核心类库,在JVM源代码中这样写道: static const char classpathFormat[] = "%/lib/rt.jar:" "%/lib/i18n.jar:" "%/lib/sunrsasign.jar:" "%/lib/jsse.jar:" "%/lib/jce.jar:" "%/lib/charsets.jar:" "%/classes"; Extension ClassLoader用来加载扩展类,即/lib/ext中的类。 最后AppClassLoader才是加载Classpath的。 ClassLoader加载类用的是委托模型。即先让Parent类(而不是Super,不是继承关系)寻找,Parent找不到才自己找。三者的关系为:AppClassLoader的Parent是ExtClassLoader,而ExtClassLoader的Parent为Bootstrap ClassLoader。加载一个类时,首先BootStrap先进行寻找,找不到再由ExtClassLoader寻找,最后才是AppClassLoader。为什么要设计的这么复杂呢?其中一个重要原因就是安全性。比如在Applet中,如果编写了一个java.lang.String类并具有破坏性。假如不采用这种委托机制,就会将这个具有破坏性的String加载到了用户机器上,导致破坏用户安全。但采用这种委托机制则不会出现这种情况。因为要加载java.lang.String类时,系统最终会由Bootstrap进行加载,这个具有破坏性的String永远没有机会加载。

gc的工作原理迟早会写篇文章介绍下的,哈哈。敬请期待吧!!

读书人网 >编程

热点推荐