`
冰糖葫芦
  • 浏览: 293863 次
社区版块
存档分类
最新评论

Java类加载器工作原理

阅读更多

Java类加载器是用来在运行时加载(*.class文件)。Java类加载器基于三个原则:委托、可见性、唯一性。委托原则把加载类的请求转发给父 类加载器,而且仅加载类当父 类加载器无法找到或者不能加载类时。可见性原则允许子类加载器查看由父类加载器加载的所有的类,但是父类加载器不能查看由子类加载器加载的类。唯一性原则 只允许加载一次类文件,这基本上是通过委托原则来实现的并确保子类加载器不重新加载由父类加载器加载过的类。正确的理解类加载器原理必须解决像 NoClassDefFoundError in Java、 java.lang.ClassNotFoundException(这些现象和加载类有关系)的问题。类加载器在高级Java面试中也是一个重要的课 题,在此场合中对类加载器和类路径的工作原理有一定的了解是Java程序员所预期的。我在各种Java面试中经常遇见这样的问题:在Java中一个类可以 被两个不同的类加载器加载吗?在本文中,我们将学习什么是Java中的类加载器、它的工作原理以及与它有关的一些细节。

 

Java的类加载器是什么

Java 中的类加载器是加载Java类文件(*.class)的一个类。Java代码被javac 编译器编译后以字节码的形式保存到类文件,JVM(Java虚拟机)通过操作类文件里的字节码来执行Java程序。类加载器负责从文件系统、网络或任何其 它资源中加载类文件。Java中使用的默认类加载器有以下三种:Bootstrap , Extension以及System or Application class loader。每个类加载器都有一个预定义的位置,它们在那里加载类文件。Bootstrap 类加载器负责从rt.jar中加载标准JDK类文件,并且它是Java中所有类加载器的父级。Bootstrap类加载器没有任何父级,如果你调用String.class.getClassLoader() 则返回null 而且与此相关的代码则抛出空指针异常。Bootstrap类加载器在java中也被称为Primordial ClassLoader(原生类加载器)Extension类加载器委托它的父级Bootstrap类加载器来加载类文件,如果委托失败,则从指向java.ext.dirs 系统属性的jre/lib/ext目录或者任何其它目录加载类文件。JVM中的Extension类加载器被sun.misc.Launcher$ExtClassLoader实现。JVM 使用的第三种默认类加载器就是System or Applicationclass loader,它主要负责从CLASSPATH环境变量中加载应用程序特定的类文件,-classpath or -cp 命令行选项, JAR内部清单文件的类路径属性。Application类加载器是Extension类加载器的子级,它由sun.misc.Launcher$AppClassLoader类实现而且,除Bootstrap 类加载器(大都由C 语言实现)以外,所有的Java类加载器使用java.lang.ClassLoader 来实现。

简而言之,这三种类加载器加载类文件的路径如下:

1) Bootstrap ClassLoader - JRE/lib/rt.jar

2) Extension ClassLoader - JRE/lib/ext 或者任何指向java.ext.dirs的路径

3) Application ClassLoader - CLASSPATH环境变量、-classpath or -cp 命令行选项,

JAR内部清单文件的类路径属性

 

 

Java类加载器工作原理

正如我前面所描述的那样,java类加载器基于三个原则:委托、可见性、唯一性。在本节中我们将看到这些原则的细节之处以及通过示例来理解java类加载器工作原理。顺便说一句,这里有一个关系图,它解释了在java中通过使用委托类加载器如何加载类文件。

 

委托原则

在探讨java中的类文件在什么时候被加载和初始化的问题时,java中的类文件在它被需要的时候被加载。假设您有一个叫做Abc.class 的应用程序特定的类文件,加载这个类文件的第一个请求发送到 Application类加载器。Application类加载器委托它的父级Extension类加载器,而Extension类加载器委托给Bootstrap类加载器。Bootstrap类加载器在rt.jar 中寻找类文件,由于没有找到,请求转发到Extension类加载器。Extension类加载器在jre/lib/ext目录中寻找类文件并尝试加载类文件,如果找到了类文件,这时Extension类加载器将会加载类文件(Application类加载器将永远不会加载类文件);但是如果Extension类加载器没有加载类文件,那么Application类加载器将会从java类路径中加载类文件。请注意:类路径用于加载类文件,而路径用来查找可执行的像javac or java 的命令。

 

可见性原则

根据可见性原则,子级类加载器可以看到父级类加载器加载的类文件,但是反过来则行不通。这意味着,假如Application类加载器加载了Abc.class 文件,那么尝试使用Extension类加载器去加载Abc.class 文件,则会抛出异常java.lang.ClassNotFoundException。请看下面的示例:

packagetest;

importjava.util.logging.Level;
importjava.util.logging.Logger;

/**
 * Java program to demonstrate How ClassLoader works in Java,
* in particular about visibilityprinciple of ClassLoader.
*
 * @author Javin Paul
 */

public class ClassLoaderTest {

public static void main(String args[]){
try{
//printingClassLoader of this class
System.out.println("ClassLoaderTest.getClass().getClassLoader(): "
+ ClassLoaderTest.class.getClassLoader());


//tryingto explicitly load this class again using Extension class loader
Class.forName("test.ClassLoaderTest",true
                            ,  ClassLoaderTest.class.getClassLoader().getParent());
}catch(ClassNotFoundExceptionex){
Logger.getLogger(ClassLoaderTest.class.getName()).log(Level.SEVERE,null, ex);
}
}

}

 

Output:

ClassLoaderTest.getClass().getClassLoader() : sun.misc.Launcher$AppClassLoader@601bb1
16/08/20122:43:48 AM test.ClassLoaderTestmain
SEVERE: null
java.lang.ClassNotFoundException:test.ClassLoaderTest
        at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
        at java.security.AccessController.doPrivileged(NativeMethod)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
        at sun.misc.Launcher$ExtClassLoader.findClass(Launcher.java:229)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
        at java.lang.Class.forName0(NativeMethod)
        at java.lang.Class.forName(Class.java:247)
        at test.ClassLoaderTest.main(ClassLoaderTest.java:29)

 

 

唯一性原则

根据这个原则,一个类文件被父级类加载器加载后,子级类加载器则不能加载它。尽管完全可以编写一个类加载器,它自己加载类文件,这违反了委托和唯一性原则,这样做没有什么好处。在您编写您自己的类加载器时,您应当遵守所有的类加载器原则。

 

java中如何准确加载类
java 提供了API通过Class.forName(classname) 和Class.forName(classname, initialized, classloader)方法来明确加载一个类,还记得JDBC中用来加载JDBC驱动的方式吗,就是使用该机制来加载对应的类。就像我们在上边例子中展 示的一样,你可以将加载特定类的加载器的名称连同类的二进制名称一起作为参数传进来。Class是通过调用java.lang.ClassLoader的 loadClass()方法,该方法又会调用findClass()方法来为相应类查找对应的字节码。在这个例子中扩展类加载器使用 java.lang.URLClassLoader用来在jar包和目录中查找类文件以及资源。其中,查询中所有以"/"结尾的的都会被当作目录处理。如 果findClass()方法没有找到相关类,那么它会抛出java.lang.ClassNotFoundException异常;如果该方法找到了相 关类,它会调用defineClass()方法来将字节码转换为.class的实例并将该实例返回给调用者。

java中在里使用类加载器
在 Java中类加载器是一个强有力的概念,在许多地方都有使用。其中比较流行的一个例子就是applet中用来加载类的AppletClassLoader 类加载器,由于applet是从互联网上加载而不是从本地文件系统中来加载类。通过使用单独的类加载器可以从多个不同的资源中加载多次相同的类,并且这些 类在JVM中会被当作不同的类对待。J2EE使用不同的类加载器从不同的位置来加载类,比如war包中的类是通过Web-app类加载器来加载,而在 EJB-JAR包中绑定的类则通过其他的类加载器加载。而一些web服务器也支持热部署功能,这都是通过实现ClassLoader来达到目的的。同时也 可以使用ClassLoader来从数据库或者其他持久化存储系统中来加载类。
这就是所有关于java中的类加载器及其工作原理。我们已经了解了委托机制、可见性、唯一性原则,这些对代码调试或者解决java中类加载器相关问题时都很重要。总而言之,类加载器工作原理对每一位设计java应用和包的开发者和架构师所必备的知识。

 

 

1. 本文由程序员学架构摘

2. 本文译自http://javarevisited.blogspot.com/2012/12/how-classloader-works-in-java.html?m=1

3. 转载请务必注明本文出自程序员学架构(微信号:archleaner )

4. 更多文章请扫码:

分享到:
评论

相关推荐

    自定义Java类加载器

    看完一个Java加载原理教程后,写了这个自己的类加载器,作个笔记,以便以且使用

    Java类加载器原理

    自己根据一些文章总结的,不知道有没有漏洞,希望大家知道,谢谢

    java类加载原理分析

    java类加载原理分析,引导类加载器,扩展类加载器,系统类加载器(也叫应用类加载器)

    深入理解java类加载机制

    此外,我们还会探讨Java程序的类加载器和双亲委派机制,以及自定义类加载器和类卸载的实现原理和应用方法。 总的来说,本资源将为Java程序员提供全面的Java字节码和类加载原理和实践经验。通过学习本资源,开发人员将...

    java的ClassLoader类加载器机制

    jvm运行的过程中,需要载入类,而类的加载需要类加载器,本文章提供了java的类加载器的工作原理。可以使读者更加理解jvm的运行机制。

    Java基础加强之类加载器

    学习概述:本模块深入讲解了Java类加载方面的知识,Java类加载器和类加载机制以及类加载原理  学习目标:掌握类加载机制和原理,能够独立开发自己的类加载器。  1.类的加载  什么是类加载? 类加载是指将类的...

    JAVA的类加载器的工作原理.pdf

    。。。

    JAVA的类加载器的工作原理.docx

    。。。

    Java类加载器层次结构原理解析

    主要介绍了Java类加载器层次结构原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    JVM类加载器说明文档

    介绍Java类的加载机制,对于深入理解Java的深层原理很有帮助

    Java实现的自定义类加载器示例

    主要介绍了Java实现的自定义类加载器,结合具体实例形式分析了java自定义类加载器的原理与具体实现技巧,需要的朋友可以参考下

    Java类加载器和类加载机制实例分析

    主要介绍了Java类加载器和类加载机制,结合实例形式分析了java类加载器与类加载机制原理、实现方法及相关操作技巧,需要的朋友可以参考下

    【图解版】深入分析ClassLoader类加载工作机制

    【图解版】深入分析ClassLoader类加载工作机制,从原理到JVM的装载过程,详情分析了ClassLoader加载类以及自定义类加载器的过程,不可用于商业用途,如有版权问题,请联系删除!

    深入研究Java 的类加载机制

    Java 类的动态装载机制是Java 虚拟机的一项核心技术,可以在运行时刻动态地加载或替换系统的 某些功能模块,而不影响系统其它功能模块的正常运行。介绍了Java 虚拟机中类的动态装载机制的原理、实现 及应用,分析了...

    面试必问之jvm与性能优化

    委托模型机制的工作原理很简单:当类加载器需要加载类的时候,先请示其Parent(即上一层加载器)在其搜索路径载入,如果找不到,才在自己的搜索路径搜索该类。这样的顺序其实就是加载器层次上自顶而下的搜索,因为加载...

    java源码包---java 源码 大量 实例

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...

    java中jvm原理和实现

    涉及到类加载器、运行时数据区、执行引擎和垃圾收集器等组件。JVM通过加载字节码文件,将其转换为JVM内部的数据结构,并存储在运行时数据区中。然后通过执行引擎将字节码指令转换为机器码并执行。同时,JVM还负责...

    AlanCheen#ReadingNotes#第2章-Java并发机制的底层实现原理1

    第2章-Java并发机制的底层实现原理Java 代码在编译后会变成 Java 字节码,字节码被类加载器加载到 JVM 里,JVM 执行字节码,最终需要转化为汇编

    大厂真题之携程-Java高级

    Java 中的所有类,都需要由类加载器装载到 JVM 中才能运行。类加 载器本身也是一个类,而它的工作就是把 class 文件从硬盘读取到内 存中。在写程序的时候,我们几乎不需要关心类的加载,因为这些都 是隐式装载的,...

    java反射机制原理详解.docx

    我们创建一个类,通过编译,生成对应的.calss文件,之后使用java.exe加载(jvm的类加载器)此.class文件,此.class文件加载到内存以后,就是一个运行时类,存在缓存区,那么这个运行时类的本身就是一个class的实例 ...

Global site tag (gtag.js) - Google Analytics