一切都是由Bootstrap Loader开始:类加载器的阶层体系
Java程序在编译之后会产生许多的执行单位(.class),当我们执行主类时(public static void main(String arg[])方法的类),才由虚拟机一一载入所有需要的执行单位,变成一个逻辑上为一体的Java应用程序。下面将细部讨论这整个流程。
当我们在命令行输入java xxx.class时,java.exe根据我们之前所提过的逻辑找到JRE,接着找到在JRE之中的jvm.dll(真正的Java虚拟机),最后载入这个动态连结函数库,启动Java虚拟机。
虚拟机一启动,会先做一些初始化的动作,比方说抓取系统参数等。一旦初始化动作完成之后,就会产生第一个类加载器,即所谓的Bootstrap Loader,Bootstrap Loader是由C++编写的。这个Loader所做的初始化工作中,除了也做一些基本的初始化动作之外,最重要的就是载入定义在sun.msic命名空间底下的Launcher.java之中的ExtClassLoader(因此是inner class,所以编译之后会变成Launcher$ExtClassLoader.class),并设定其parent为null,代表其父类加载器为Bootstrap Loader。然后Bootstrap Loader再要求载入定义在sun.misc命名空间下的Launcher.java之中的AppClassLoader(因此是inner class,所以编译之后会变成Launcher$AppClassLoader.class),并设定其parent为之前产生的ExtClassLoader实例。这里需要注意的是:Launcher$ExtClassLoader.class与Launcher$AppClassLoader.class都是由Bootstrap Loader所载入,所以parent和由那个类加载器载入没有关系。可以用下图表示:
AppClassLoader在sun官方文件中常常又被称作系统加载器(System Loader)。最后一个步骤,是由AppClassLoader负责载入我们在命令行之中所输入的xxx.class(注意:实际上xxx.class很可能是由ExtClassLoader或Bootstrap Loader载入,参考下一篇博文的【委派模型】),然后开始一个Java应用程序的生命周期。整个流程如下图:
这个由Bootstrap Loader-->ExtClassLoader-->AppClassLoader,就是我们所谓的类加载器的阶层体系。
再次强调,类加载器由谁载入(这句话有点诡异,类加载器也要由类加载器载入,这是因为除了Bootstrap Loader之外,其余的类加载器都是由Java所编写),和它的parent是谁没有关系,parent的存在只是为了某些特殊目的,这个目的之后再作解析。三个主要的加载器的关系如下图:
在此要注意的是,AppClassLoader和ExtClassLoader都是URLClassLoader的子类。由于它们都是URLClassLoader的子类,所以它们也应该有URL作为搜索类的参考,由源代码我们可以得知:
AppClassLoader所参考的URL是从系统参数java.class.path取出的字符串所决定,而java.class.path则是由我们在执行java.exe时,利用-cp或-classpath或CLASSPATH环境变量所决定。在预设定情况下,AppClassLoader的搜索路径为"."(目前所在目录),如果使用-classpath(与-cp等效),就可以改变AppClassLoader的搜索路径,如果没有指定-classpath,就会搜索环境变量CLASSPATH。
ExtClassLoader搜索路径参考系统参数java.ext.dirs,会指向java.exe所选择的JRE所在位置下的\lib\ext子目录。
Bootstrap Loader的搜索路径由系统参数sun.boot.class.path指定。
注意:AppClassLoader和Bootstrap Loader只会搜索指定的路径,不会迂回搜索这些位置下的其他路径或者没有指定的JAR文件。而ExtClassLoader会搜索底下所有的JAR文件以及classes目录,作为其搜索路径。
AppClassLoader和ExtClassLoader在整个虚拟机中只存在一份,一旦建立了,其内部所参考的搜索路径将不再改变,也就是说,即使我们在程序里利用System.setProperty()来改变系统参数的内容,仍然无法更改搜索路径。因此,执行时期动态更改搜索路径的设定是不可能的事情。如果因为特殊需求,有些类的所在路径并非在一开始时就能决定,那么除了产生新的类加载器来辅助我们载入所需要的类之外,没有其它方法了。
来源:https://www.cnblogs.com/rason2008/archive/2012/01/07/2316122.html