java类加载器——ClassLoader

Java的设计初衷是主要面向嵌入式领域,对于自定义的一些类,考虑使用依需求加载原则,即在程序使用到时才加载类,节省内存消耗,这时即可通过类加载器来动态加载。

如果你平时只是做web开发,那应该很少会跟类加载器打交道,但如果你想深入学习tomcat服务器的架构,它是必不可少的。所谓类加载器,就是用于加载Java类到Java虚拟机中,它负责读取Java字节码,并转换成java.lang.Class类的一个实例,使字节代码.class文件得以运行。一般类加载器负责根据一个指定的类找到对应的字节代码,然后根据这些代码定义成一个Java类,另外还负责加载资源,包括图像文件和配置文件。

类加载器在实际使用中给我们带来的好处是,它可以使Java类动态地加载到JVM并运行,即可在程序运行时再加载类,提供了很灵活的动态加载方式。例如我们熟悉的Applet,从远程服务器下载字节码到客户端动态加载到JVM便可以运行。

在Java的庞大体系中,可以将系统分为三种类加载器,分别是:

①   启动类加载器(Bootstrap ClassLoader):加载对象是Java核心库,把一些关键的Java类加载进JVM,这个加载器使用原生代码(C/C++)实现的,并不是继承java.lang.ClassLoader,它是所有其他类加载器的最终父加载器,负责加载<JAVA_HOME>/jre/lib目录下且被JVM指定的类库,其实它属于JVM整体的一部分,JVM一启动就将这些指定的类加载到内存中,避免以后过多的I/O操作,提高系统的运行效率。启动类加载器无法被Java程序直接使用。

②   扩展类加载器(Extension ClassLoader):加载的对象为Java的扩展库,即加载<JAVA_HOME>/jre/lib/ext目录里面的类。这个类由上面的Bootstrap ClassLoader加载,但由于Bootstrap ClassLoader并非用Java实现,已经脱离了Java体系,所以如果尝试调用扩展类加载器的getParent()方法获取父加载器会得到null,但它的父类加载器是Bootstrap ClassLoader。Java中可以直接使用扩展类加载器。

③   应用程序类加载器(Application  ClassLoader):亦叫系统类加载器(System ClassLoader),它负责加载用户类路径(CLASSPATH)指定的类库,如果程序没有自己定义类加载器,就默认使用应用程序类加载器。它也由Bootstrap ClassLoader加载,但它的父加载类被设置成了Extension ClassLoader。如果要使用这个加载器,可通过ClassLoader.getSystemClassLoader()获取。

假如有一天你心血来潮也想自己写一个类加载器,那么你只需要继承java.lang.ClassLoader类即可。于是可以用下面的图2-4-1来清晰表示出各种类加载器的关系,Bootstrap ClassLoader是最根本的类加载器,其不存在父类加载器,Extension ClassLoader由Bootstrap ClassLoader加载,所以它的父类加载器是Bootstrap ClassLoader,Application ClassLoader也是由Bootstrap ClassLoader加载,但它的父加载器被指向了Extension
ClassLoader,而其他所有用户自定义的类加载器都由Application ClassLoader加载。

由此可以看出越重要的类加载器就越早被JVM载入,这是考虑到安全性,因为先加载的类加载器会充当下一个类加载器的父加载器,在双亲委派模型机制下,就能确保安全性。

那么什么是双亲委派模型?比如爷爷、爸爸、你三代单传,你们家族都遗传懒惰基因,每当遇到事情都互相推脱,现在需要一个人去买一包盐,不然今晚的菜就有色无味了,而你第一个被委托去超市买,但由于你的懒惰,你向你爸爸撒了一顿娇,你爸爸受不了你只能答应帮你去,在懒惰的驱使下,你爸爸最后找了一个借口说要赶工作,让你爷爷出去走动走动顺便买一包盐,就这样你爷爷只能乖乖去超市买盐。双亲委派模型就类似这样的机制,类加载器加载类时首先委托给父类加载器加载,除非父类加载器不能加载才自己加载。

这种模型要求除了顶层的启动类加载器外,其他的类加载器都要有自己的父类加载器。假如有一个类要加载进来,一个类加载器并不会马上尝试自己将其加载,而是委派到父类加载器,父类加载器收到后又尝试委派到其父类加载器,以此类推,直到委派到启动类加载器,这样一层一层往上委派。只有当父类加载器反馈自己没法完成这个加载时,子加载器才会尝试自己加载。通过这个机制,保证了Java应用所使用的都是同一个版本的Java核心库的类。同时这个机制也保证了安全性,设想如果Application ClassLoader想要加载一个有破坏性的java.lang.System类,双亲委派模型会一层层向上委派,最终委派给Bootstrap
ClassLoader,而Bootstrap ClassLoader检查到缓存中已经有了这个类,并不会再加载这个有破坏性的System类。

另外,类加载器还拥有全盘负责机制,即当一个ClassLoader加载一个类时,这个类所依赖的、引用的其他所有类都由这个ClassLoader加载,除非在程序中显性地指定另外一个ClassLoader加载。

图2-4-1 类加载器关系

在Java中,我们用完全匹配类名来标识一个类,即用包名和类名。而在JVM中,一个类由完全匹配类名和一个类加载器的实例ID作为唯一标识。即是说同一个虚拟机可以有两个包名、类名都相同的类,只要他们由两个不同类加载器加载。于是当我们在Java中经常说两个类相不相等,必须是针对同一个类加载器加载的前提下才有意义,否则就算是同样的字节代码,由不同类加载器加载,这两个类也不是相等的。这种特征为我们提供了隔离机制,在tomcat服务器中是十分有用的。

了解了JVM的类加载器的各种机制后,看看一个类是怎样被类加载器载入进来的。一个类准备加载,类加载器先判断此类是否已经被加载过(加载过的类会被缓存在内存中),如果缓存中存在此类则直接返回这个类。否则获取父类加载器,如果父类加载器为null,则由Bootstrap ClassLoader载入并返回Class。如果父类加载器不为null,则由父类加载器载入,载入成功就返回Class,载入失败则根据类路径查找class文件,找到就加载此class并返回Class,找不到就抛出ClassNotFoundException异常。

图2-4-2 类加载过程

类加载器属于JVM级别的设计,我们很多时候基本不会跟他打交道,但是假如你想了解整个JAVA体系是如何工作的,假如你要设计开发自己的框架或中间件或一个较庞大的java软件,那么你必须熟悉类加载器的相关机制,在现实的设计中,根据实际情况利用类加载器可以提供类库的隔离及共享,保证你的软件不同级别的逻辑分割程序不会互相影响,提供更好的安全性。

java类加载器——ClassLoader,布布扣,bubuko.com

时间: 2024-08-02 02:47:33

java类加载器——ClassLoader的相关文章

浅析java类加载器ClassLoader

作为一枚java猿,了解类加载器是有必要的,无论是针对面试还是自我学习. 本文从JDK提供的ClassLoader.委托模型以及如何编写自定义的ClassLoader三方面对ClassLoader做一个简要的总结. JDK中提供的ClassLoader 1. Bootstrap ClassLoader Bootstrap加载器是用C++语言写的,它是在Java虚拟机启动后初始化的,它主要负责加载%JAVA_HOME%/jre/lib以及%JAVA_HOME%/jre/classes中的类,是最顶

深入理解 java类加载器ClassLoader

类加载器(class loader)用来加载 Java 类到 Java 虚拟机中.一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件).类加载器负责读取 Java 字节代码,并转换成java.lang.Class类的一个实例.每个这样的实例用来表示一个 Java 类.通过此实例的 newInstance()方法就可以创建出该类的一个对象,也就是万能的Class对象. Jav

Java类加载器( CLassLoader ) 死磕 3: 揭秘 ClassLoader抽象基类

[正文]Java类加载器(  CLassLoader ) 死磕3:  揭秘 ClassLoader抽象基类 3.1. 揭秘ClassLoader抽象基类 3.1.1. 类的加载分类:隐式加载和显示加载 java中类是动态加载的,jvm启动的时候,并不会一次性加载所有的class文件,而是根据需要去动态加载.一是加快启动的速度,二是节约内存.如果一次性加载全部jar包的所有class,速度会很慢. 动态载入一个class类,有两种方式: (1) implicit隐式加载 即通过实例化才载入的特性来

【正文】Java类加载器( CLassLoader ) 死磕 4: 神秘的双亲委托机制

[正文]Java类加载器(  CLassLoader ) 死磕4:  神秘的双亲委托机制 本小节目录 4.1. 每个类加载器都有一个parent父加载器 4.2. 类加载器之间的层次关系 4.3. 类的加载次序 4.4 双亲委托机制原理与沙箱机制 4.5. forName方法和loadClass方法的关系 4.6. 使用组合而不用继承 4.7. 各种不同的类加载途径 4.1.每个类加载器都有一个parent父加载器 每个类加载器都有一个parent父加载器,比如加载SystemConfig.cl

Java类加载器ClassLoader总结

JAVA类装载方式,有两种: 1.隐式装载, 程序在运行过程中当碰到通过new 等方式生成对象时,隐式调用类装载器加载对应的类到jvm中. 2.显式装载, 通过class.forname()等方法,显式加载需要的类 类加载的动态性体现: 一个应用程序总是由n多个类组成,Java程序启动时,并不是一次把所有的类全部加载后再运行,它总是先把保证程序运行的基础类一次性加载到jvm中,其它类等到jvm用到的时候再加载,这样的好处是节省了内存的开销,因为java最早就是为嵌入式系统而设计的,内存宝贵,这是

Java类加载器ClassLoader的说明

(1)API文档内容如下: 类加载器是负责加载类的对象.ClassLoader 类是一个抽象类.如果给定类的二进制名称,那么类加载器会试图查找或生成构成类定义的数据.一般策略是将名称转换为某个文件名,然后从文件系统读取该名称的"类文件". 每个 Class 对象都包含一个对定义它的 ClassLoader 的引用. 数组类的 Class 对象不是由类加载器创建的,而是由 Java 运行时根据需要自动创建.数组类的类加载器由 Class.getClassLoader() 返回,该加载器与

潜水 java类加载器ClassLoader

类加载器(class loader)用于装载 Java 类到 Java 虚拟机中.一般来说.Java 虚拟机使用 Java 类的方式例如以下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件).类载入器负责读取 Java 字节代码.并转换成java.lang.Class类的一个实例.每一个这种实例用来表示一个 Java 类. 通过此实例的 newInstance()方法就能够创建出该类的一个对象,也就是万能的Class对象.

深入源码看java类加载器ClassLoader

ClassLoader类加载器是负责加载类的对象.ClassLoader 类是一个抽象类.如果给定类的二进制名称(即为包名加类名的全称),那么类加载器会试图查找或生成构成类定义的数据.一般策略是将名称转换为某个文件名,然后从文件系统读取该名称的"类文件".java.lang.ClassLoader类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个 Java 类,即 java.lang.Class类的一个实例.除此之外,ClassLoad

Java类加载器 ClassLoader的解析

//参考 : http://www.ibm.com/developerworks/cn/java/j-lo-classloader/ 类加载器基本概念 类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一.它使得 Java 类可以被动态加载到 Java 虚拟机中并执行.类加载器从 JDK 1.0 就出现了,最初是为了满足 Java Applet 的需要而开发出来的.Java Applet 需要从远程下载 Java 类文件到浏览器中并执行.现在类加载器在 Web 容器和 O