classloader 简单介绍

来源:互联网 发布:网络培训课程 编辑:程序博客网 时间:2024/06/05 08:44

文章摘抄至http://longdick.iteye.com/blog/442213/

 

要深入了解ClassLoader,首先就要知道ClassLoader是用来干什么的,顾名思义,它就是用来加载Class文件到JVM,以供程序使用的。我们知道,java程序可以动态加载类定义,而这个动态加载的机制就是通过ClassLoader来实现的,所以可想而知ClassLoader的重要性如何。 

 

看到这里,可能有的朋友会想到一个问题,那就是既然ClassLoader是用来加载类到JVM中的,那么ClassLoader又是如何被加载呢?难道它不是java的类? 

 

没有错,在这里确实有一个ClassLoader不是用java语言所编写的,而是JVM实现的一部分,这个ClassLoader就是bootstrap classloader(启动类加载器),这个ClassLoader在JVM运行的时候加载java核心的API以满足java程序最基本的需求,其中就包括用户定义的ClassLoader,这里所谓的用户定义是指通过java程序实现的ClassLoader,一个是ExtClassLoader,这个ClassLoader是用来加载java的扩展API的,也就是/lib/ext中的类,一个是AppClassLoader,这个ClassLoader是用来加载用户机器上CLASSPATH设置目录中的Class的,通常在没有指定ClassLoader的情况下,程序员自定义的类就由该ClassLoader进行加载。 


 

当运行一个程序的时候,JVM启动,运行bootstrap classloader,该ClassLoader加载java核心API(ExtClassLoader和AppClassLoader也在此时被加载),然后调用ExtClassLoader加载扩展API,最后AppClassLoader加载CLASSPATH目录下定义的Class,这就是一个程序最基本的加载流程

 

java应用环境中不同的class分别由不同的ClassLoader负责加载。
一个jvm中默认的classloader有Bootstrap ClassLoader、Extension ClassLoader、App ClassLoader,分别各司其职:

  • Bootstrap ClassLoader      负责加载java基础类,主要是 %JRE_HOME/lib/ 目录下的rt.jar、resources.jar、charsets.jar和class等
  • Extension ClassLoader       负责加载java扩展类,主要是 %JRE_HOME/lib/ext 目录下的jar和class
  • App ClassLoader           负责加载当前java应用的classpath中的所有类。

其中Bootstrap ClassLoader是JVM级别的,由C++撰写;Extension ClassLoader、App ClassLoader都是java类,都继承自URLClassLoader超类。
Bootstrap ClassLoader由JVM启动,然后初始化sun.misc.Launcher ,sun.misc.Launcher初始化Extension ClassLoader、App ClassLoader。

下图是ClassLoader的加载类流程图,以加载一个类的过程类示例说明整个ClassLoader的过程。

public class ClassLoaderTree {public static void main(String[] args) {ClassLoader loader = ClassLoaderTree.class.getClassLoader();/** sun.misc.Launcher$AppClassLoader@39ab89 系统类加载器 sun.misc.Launcher$ExtClassLoader@2cb49d 扩展类加载器 */while(loader != null){System.out.println(loader.toString());loader = loader.getParent();}}}

 

Bootstrap ClassLoader、Extension ClassLoader、App ClassLoader三者的关系如下:

Bootstrap ClassLoader是Extension ClassLoader的parent,Extension ClassLoader是App ClassLoader的parent。但是这并不是继承关系,只是语义上的定义,基本上,每一个ClassLoader实现,都有一个Parent ClassLoader。

 

可以通过ClassLoader的getParent方法得到当前ClassLoader的parent。Bootstrap ClassLoader比较特殊,因为它不是java class所以Extension ClassLoader的getParent方法返回的是NULL。

 

当使用ClassLoader类的loadClass()方法来加载某个类时,该方法只是加载该类,并不会执行该类的初始化。使用Class的forName()静态方法才会导致强制初始化该类。

package hb.reflect;public class Tester{static{System.out.println("初始化块");}}

 

package hb.reflect;public class ClassLoaderTest {public static void main(String[] args) throws ClassNotFoundException {ClassLoader c1 = ClassLoader.getSystemClassLoader();//不会执行初始化c1.loadClass("hb.reflect.Tester");System.out.println("系统加载Tester类");//执行初始化内容Class.forName("hb.reflect.Tester");}}

 打印内容:

系统加载Tester类

初始化块

 

如果将代码如下修改:

package hb.classloader;public class ClassLoaderTest {public static void main(String[] args) throws ClassNotFoundException {ClassLoader c1 = ClassLoader.getSystemClassLoader();//不会执行初始化Class clazz = c1.loadClass("hb.classloader.Tester");//try {Tester tester = (Tester)clazz.newInstance();tester.print("class.newInstance() is ok");} catch (InstantiationException | IllegalAccessException e) {e.printStackTrace();}System.out.println("系统加载Tester类");//执行初始化内容Class.forName("hb.classloader.Tester");}}

 打印结果:

初始化块

class.newInstance() is ok

系统加载Tester类

 
备注:因为在调用getInstance()方法实际上就是创建一个无参的构造函数,因此需要初始化Tester类,所以与上面的有点区别。