[转载]http://www.blogjava.net/zhuxing/archive/2008/08/08/220841.html 1 基本信息 摘要: 每个java开发人员对java.lang.ClassNotFoundExcetpion这个异常肯定都不陌生,这背后就涉及到了java技术体系中的类加载。Java的类加载机制是java技术体系中比较核心的部分,虽然和大部分开发人员直接打交道不多,但是对其背后的机理有一定理解有助于排查程序中出现的类加载失败等技术问题,对理解java虚拟机的连接模型和java语言的动态性都有很大帮助。 由于关于java类加载的内容较多,所以打算分三篇文章简述一下: 第一篇:java类加载原理解析 第二篇:插件环境下类加载原理解析 第三篇:线程上下文类加载器 分类:开发技术->J2EE 标签:Java类加载 类加载器 双亲委派机制 自定义类加载器 作者:朱兴 创建于2007-6-22 MSN:zhu_xing@live.cn 2 Java虚拟机类加载器结构简述 2.1 JVM三种预定义类型类加载器 我们首先看一下JVM预定义的三种类型类加载器,当一个 JVM 启动的时候,Java 缺省开始使用如下三种类型类装入器: 启动(Bootstrap)类加载器:引导类装入器是用本地代码实现的类装入器,它负责将 <Java_Runtime_Home>/lib下面的类库加载到内存中。由于引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不允许直接通过引用进行操作。 标准扩展(Extension)类加载器:扩展类加载器是由 Sun 的 ExtClassLoader(sun.misc.Launcher$ExtClassLoader) 实现的。它负责将 < Java_Runtime_Home>/lib/ext 或者由系统变量 java.ext.dir指定位置中的类库加载到内存中。开发者可以直接使用标准扩展类加载器。 系统(System)类加载器:系统类加载器是由 Sun 的 AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的。它负责将系统类路径(CLASSPATH)中指定的类库加载到内存中。开发者可以直接使用系统类加载器。 除了以上列举的三种类加载器,还有一种比较特殊的类型就是线程上下文类加载器,这个将在后面单独介绍。 2.2 类加载双亲委派机制介绍和分析 在这里,需要着重说明的是,JVM在加载类时默认采用的是双亲委派机制。通俗的讲,就是某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。关于虚拟机默认的双亲委派机制,我们可以从系统类加载器和标准扩展类加载器为例作简单分析。 file:///C:/Users/river/AppData/Local/Temp/msohtmlclip1/01/clip_image005.jpg
图五 扩展类加载器和系统类加载器公共父类成员大纲视图 通过图四和图五可以看出,标准扩展类加载器和系统类加载器及其父类(java.net.URLClassLoader和java.security.SecureClassLoader)都没有覆写java.lang.ClassLoader中默认的加载委派规则---loadClass(…)方法。有关java.lang.ClassLoader中默认的加载委派规则前面已经分析过,如果父加载器为null,则会调用本地方法进行启动类加载尝试。所以,图三中,启动类加载器、标准扩展类加载器和系统类加载器之间的委派关系事实上是仍就成立的。(在后面的用户自定义类加载器部分,还会做更深入的分析)。 2.3 类加载双亲委派示例 以上已经简要介绍了虚拟机默认使用的启动类加载器、标准扩展类加载器和系统类加载器,并以三者为例结合JDK代码对JVM默认使用的双亲委派类加载机制做了分析。下面我们就来看一个综合的例子。首先在eclipse中建立一个简单的java应用工程,然后写一个简单的JavaBean如下: package classloader.test.bean; publicclass TestBean { public TestBean() {} } 在现有当前工程中另外建立一测试类(ClassLoaderTest.java)内容如下: 测试一: publicclass ClassLoaderTest { publicstaticvoid main(String[]args) { try { //查看当前系统类路径中包含的路径条目 System.out.println(System.getProperty("java.class.path")); //调用加载当前类的类加载器(这里即为系统类加载器)加载TestBean Class typeLoaded = Class.forName("classloader.test.bean.TestBean"); //查看被加载的TestBean类型是被那个类加载器加载的 System.out.println(typeLoaded.getClassLoader()); } catch (Exception e) { e.printStackTrace(); } } } 对应的输出如下: D:"DEMO"dev"Study"ClassLoaderTest"bin (说明:当前类路径默认的含有的一个条目就是工程的输出目录)
|