平台特定的启动类加载器深入分析与自定义系统类加载器详解

平台特定的启动类加载器深入分析:

这里以上一次【https://www.cnblogs.com/webor2006/p/9157626.html】的这个程序作为学习的开端,如下:

运行结果:

/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/sunrsasign.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/classes
/Users/xiongwei/Library/Java/Extensions:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java
/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/lib/tools.jar:/Users/xiongwei/Documents/workspace/IntelliJSpace/jvm_lectue/out/production/classes

可见不同的系统类加载器所加载的目录是不一样的,那如果换成用java命令来执行这个程序会有啥不同呢,先进入该字节码文件所在的目录:

那为啥通过IDE运行看到应用类加载器的目录有这么多呢?这是因为IntelliJ IDEA在运行时会在classPath中增加一些特定的目录,而通过java命令执行此时就脱离开了Intellij IDEA了,所以只有一个当前为点的路径了,当然IntelliJ IDEA运行时也包含了当前目录的路径,如下:

另外回顾一下这个理论:“在运行期,一个Java类是由该类的完全限定名(binary name, 二进制名)和用于加载该类的定义类加载器(defining loader)所共同决定的。如果同样名字(既相同的完全限定名)的类是由两个不同的加载器所加载,那么这些类就是不同的,既便.class文件的字节码完全一样,并且从相同的位置加载亦如此。”

接下来如果咱们改变启动类加载器的加载目录,那结果会如何呢,下面来试一下:

接下来思考一个问题:类加载器的作用是用来加载类的,但是对于类加载器(如扩展类加载器ExtClassLoader、应用类加载器AppClassLoader)也是一个java文件,那它们是由谁来加载到JVM当中的呢?其实扩展类加载器和应用类加载器都是由启动类加载器所加载的,而启动类加载器是由C++来实现的,并非是java文件,它是内建于JVM当中的,也就是归属于JVM的一部分,也就是JVM启动时启动类加载器就会被创建,也就是说:内建于JVM中的启动类加载器会加载java.lang.ClassLoader以及其它的Java平台类,当JVM启动时,一块特殊的机器码会运行,它会加载扩展类加载器与系统类加载器,这块特殊的机器码叫做启动类加载器(Bootstrap),而启动类加载器并不是Java类,而其它的加载器则都是Java类,启动类加载器是特定于平台的机器指令,它负责开启整个加载过程。所有类加载器(除了启动类加载器)都被实现为Java类,不过总归要有一个组件来加载第一个Java类加载器,从而让整个加载过程能够顺利进行下去,加载第一个纯Java类加载器就是启动类加载器的职责。启动类加载器还会负责加载供JRE正常运行所需要的基本组件,这包括java.util与java.lang包中的类等等。

接下来修改一下代码:

那对于AppClassLoader和ExtClassLoader加载器如何来论证它们也是由启动类加载器所加载的呢,直接校仿上面打印ClassLoader去做不就可以了么,答案是不可以的,为什么,因为这两个类是Laucher的内部类,而且这两个内部类不是public的,也就是外面没法去访问的,如下:

那不没办法来论证了,其实不然,既然它们是Launcher类的内部类,那只要论证Launcher类是由启动类加载的,那它里面的内部类也相应的会得到加载,所以下面来论证一下:

另外对于咱们程序中使用的这些东东都来源于哪里呢,如下:

其它它都来源于Launcher类中,如下:

自定义系统类加载器详解:

对于系统类加载器(也就应用类加载器)可以通过如下获得:

而在之前【https://www.cnblogs.com/webor2006/p/9029910.html】咱们已经简单读过它的javadoc了,这里再来看一下这块:

也就是说可以自定义系统类加载器,下面来打印一下javadoc上出现的这个属性:

接下来咱们想把自己写的自定义的类加载器MyTest16作为自定义的系统类加载器:

还是可以通过java运行期来修改系统属性来实现,如下:

为啥?其实原因来自于javadoc,看这里:

所以这里需要修改一下咱们自定义的类加载器MyTest16,如下:

然后再次编译,再运行:

接下来继续修改程序:

好,接下来继续修改:

此时如果换到java命令行来执行呢,如下:

这是为啥呢?这里待之后再进一步观察。

posted on 2018-06-25 22:16  cexo  阅读(371)  评论(0编辑  收藏  举报

导航