JAVA系统类加载器

JAVA系统类加载器

三个加载器类

Bootstrap ClassLoader

最顶层的加载类,主要加载核心类库,JRE_HOME\lib下的rt.jar、resources.jar、charsets.jar和class等。另外需要注意的是可以通过启动jvm时指定-Xbootclasspath和路径来改变Bootstrap ClassLoader的加载目录。Bootstrap ClassLoader是由C/C++编写的,它本身是虚拟机的一部分,所以它并不是一个JAVA类,也就是无法在java代码中获取它的引用,JVM启动时通过Bootstrap类加载器加载rt.jar等核心jar包中的class文件,int.class,String.class都是由它加载。JVM初始化sun.misc.Launcher并创建Extension ClassLoader和AppClassLoader实例。并将ExtClassLoader设置为AppClassLoader的父加载器。Bootstrap没有父加载器,但是它却可以作用一个ClassLoader的父加载器。比如ExtClassLoader。这也可以解释通过ExtClassLoader的getParent方法获取为Null的现象。

//Bootstrap CLassloder 
System.out.println(System.getProperty("sun.boot.class.path"));

E:\JAVA\jdk1.8.0_171\jre\lib\resources.jar;
E:\JAVA\jdk1.8.0_171\jre\lib\rt.jar;
E:\JAVA\jdk1.8.0_171\jre\lib\sunrsasign.jar;
E:\JAVA\jdk1.8.0_171\jre\lib\jsse.jar;
E:\JAVA\jdk1.8.0_171\jre\lib\jce.jar;
E:\JAVA\jdk1.8.0_171\jre\lib\charsets.jar;
E:\JAVA\jdk1.8.0_171\jre\lib\jfr.jar;
E:\JAVA\jdk1.8.0_171\jre\classes

Extention ClassLoader 扩展的类加载器

加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件。还可以加载-D java.ext.dirs选项指定的目录。

//Extention ClassLoader  Launcher.ExtClassLoader
System.out.println(System.getProperty("java.ext.dirs"));

E:\JAVA\jdk1.8.0_171\jre\lib\ext;
C:\windows\Sun\Java\lib\ext

Appclass Loader

也称为SystemAppClass 加载当前应用的classpath的所有类。

//Launcher.AppClassLoader

String str=System.getProperty("java.class.path");
String [] strs=str.split(";");
for (int i=0;i{
      System.out.println(strs[i]);
}

E:\JAVA\jdk1.8.0_171\jre\lib\charsets.jar
E:\JAVA\jdk1.8.0_171\jre\lib\deploy.jar
E:\JAVA\jdk1.8.0_171\jre\lib\ext\access-bridge.jar
E:\JAVA\jdk1.8.0_171\jre\lib\ext\cldrdata.jar
E:\JAVA\jdk1.8.0_171\jre\lib\ext\dnsns.jar
E:\JAVA\jdk1.8.0_171\jre\lib\ext\jaccess.jar
E:\JAVA\jdk1.8.0_171\jre\lib\ext\jfxrt.jar
E:\JAVA\jdk1.8.0_171\jre\lib\ext\localedata.jar
E:\JAVA\jdk1.8.0_171\jre\lib\ext\nashorn.jar
E:\JAVA\jdk1.8.0_171\jre\lib\ext\sunec.jar
E:\JAVA\jdk1.8.0_171\jre\lib\ext\sunjce_provider.jar
E:\JAVA\jdk1.8.0_171\jre\lib\ext\sunmscapi.jar
E:\JAVA\jdk1.8.0_171\jre\lib\ext\sunpkcs11.jar
E:\JAVA\jdk1.8.0_171\jre\lib\ext\zipfs.jar
E:\JAVA\jdk1.8.0_171\jre\lib\javaws.jar
E:\JAVA\jdk1.8.0_171\jre\lib\jce.jar
E:\JAVA\jdk1.8.0_171\jre\lib\jfr.jar
E:\JAVA\jdk1.8.0_171\jre\lib\jfxswt.jar
E:\JAVA\jdk1.8.0_171\jre\lib\jsse.jar
E:\JAVA\jdk1.8.0_171\jre\lib\management-agent.jar
E:\JAVA\jdk1.8.0_171\jre\lib\plugin.jar
E:\JAVA\jdk1.8.0_171\jre\lib\resources.jar
E:\JAVA\jdk1.8.0_171\jre\lib\rt.jar
E:\code\java\app\out\production\classes
E:\ideaIU-2018.1.5.win\lib\idea_rt.jar

加载顺序

  1. Bootstrap CLassloder
  2. Extention ClassLoader
  3. AppClassLoader
ClassLoader classLoader=Test.class.getClassLoader();
//ClassLoader is:sun.misc.Launcher$AppClassLoader@b4aac2
System.out.println("ClassLoader is:"+classLoader.toString());

//ClassLoader's parent is:sun.misc.Launcher$ExtClassLoader@154617c      
System.out.println("ClassLoader\'s parent is:"+classLoader.getParent().toString());

//null
System.out.println("ClassLoader\'s grand father is:"+classLoader.getParent().getParent().toString());

相关源码

sun.misc.Launcher,它是一个java虚拟机的入口应用。
1. Launcher初始化了ExtClassLoader和AppClassLoader。
2. Launcher中并没有看见BootstrapClassLoader,但通过System.getProperty(“sun.boot.class.path”)得到了字符串bootClassPath,这个就是BootstrapClassLoader加载的jar包路径。

类加载机制

一个类加载器查找class和resource时,是通过“委托模式”进行的,它首先判断这个class是不是已经加载成功,如果没有的话它并不是自己进行查找,而是先通过父加载器,然后递归下去,直到Bootstrap ClassLoader,如果Bootstrap classloader找到了,直接返回,如果没有找到,则一级一级返回,最后到达自身去查找这些对象。这种机制就叫做双亲委托。

ClassLoader使用的是双亲委托模型来搜索类的,每个ClassLoader实例都有一个父类加载器的引用(不是继承的关系,是一个包含的关系),虚拟机内置的类加载器(Bootstrap ClassLoader)本身没有父类加载器,但可以用作其它ClassLoader实例的的父类加载器。当一个ClassLoader实例需要加载某个类时,它会试图在亲自搜索某个类之前,先把这个任务委托给它的父类加载器,这个过程是由上至下依次检查的,首先由最顶层的类加载器Bootstrap ClassLoader试图加载,如果没加载到,则把任务转交给Extension ClassLoader试图加载,如果也没加载到,则转交给App ClassLoader 进行加载,如果它也没有加载得到的话,则返回给委托的发起者,由它到指定的文件系统或网络等URL中加载该类。如果它们都没有加载到这个类时,则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义,并将它加载到内存当中,最后返回这个类在内存中的Class实例对象。

好处:因为这样可以避免重复加载,当父亲已经加载了该类的时候,就没有必要让子ClassLoader再加载一次。考虑到安全因素,我们试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的String来动态替代java核心api中定义的类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,因为String已经在启动时就被引导类加载器(Bootstrcp ClassLoader)加载,所以用户自定义的ClassLoader永远也无法加载一个自己写的String,除非你改变JDK中ClassLoader搜索类的默认算法。

你可能感兴趣的:(java,java,类加载)