jvm核心类加载器--jdk源码剖析 (下)
类主要通过类加载器来加载, java里面有如下几种类加载器
1. 引导类加载器:负责加载支撑JVM运行的, 位于jre目录的lib目录下的核心类. 比如:rt.jar, charset.jar等,
2. 扩展类加载器: 负责加载支撑JVM运行的, 位于jre目录的lib/ext扩展目录中的jar包
3. 应用程序类加载器: 负责加载classPath路径下的类包, 主要加载自己写的类
4. 自定义类加载器: 负责加载用户自定义路径下的类包
引导类加载器是由C 帮我们实现的, 然后c 语言会通过一个Launcher类将扩展类加载器(ExtClassLoader)和应用程序类加载器(AppClassLoader)构造出来, 并且把他们之间的关系构建好.
package com.lxl.jvm; import sun.misc.Launcher; import java.net.URL; public class TestJDKClassLoader { public static void main(String[] args) { * 第一个: String 是jdk自身自带的类, 所以, 他的类加载器是引导类加载器 * 第二个: 加密类的classloader, 这是jdk扩展包的一个类 * 第三个: 是我们当前自己定义的类, 会被应用类加载器加载 System.out.println(String.class.getClassLoader()); System.out.println(com.sun.crypto.provider.DESKeyFactory.class.getClassLoader().getClass().getName()); System.out.println(TestJDKClassLoader.class.getClassLoader().getClass().getName()); }
我们来看这个简单的代码, 运行结果:
null sun.misc.Launcher$ExtClassLoader sun.misc.Launcher$AppClassLoader
第一个: String 是jdk自身自带的类, 所以, 他的类加载器是引导类加载器
第二个: 加密类的classloader, 这是jdk扩展包的一个类, jdk扩展包里面使用的是extClassLoader类加载器加载的
第三个: 是我们当前自己定义的类, 会被AppClassLoader应用程序加载器加载.
我们看到ExtClassLoader和AppClassLoader都是Launcher类的一部分. 那Launcher类是什么东西呢?
上面有提到, Launcher类是jvm启动的时候由C 调用启动的一个类.
那么,第一个bootstrap引导类加载器, 那引导类加载器返回的为什么是null呢?
因为bootstrap引导类加载器, 他不是java的对象, 他是c 生成的对象, 所以这里是看不到的
例2: ExtClassLoader和AppClassLoader是怎么生成的?
从这个图中我们可以看出,C 调用java创建JVM启动器, 其中一个启动器是Launcher,他实际是调用了sun.misc.Launcher的getLauncher()方法. 那我们就从这个方法入手看看到底是如何运行的?
我们看到Lanucher.java类是在核心的rt.jar包里的
我们看到getLauncher()类直接返回了launcher. 而launcher是一个静态对象变量, 这是一个单例模式
C 通过getLauncher()-- 直接返回了lanucher对象, 而launcher对象是在构建类的时候就已经初始化好了. 那么,初始化的时候做了哪些操作呢?接下来看看他的构造方法.
在构造方法里, 首先定义了一个ExtClassLoader. 这是一个扩展类加载器, 扩展类加载器调用的是getExtClassLoader(). 接下来看一看getExtClassLoader这个方法做了什么?
在这里, 判断当前对象是否初始化过, 如果没有, 那么就创建一个ExtClassLoader()对象, 看看createExtClassLoader()这个方法做了什么事呢?
doPrivileged是一个权限校验的操作, 我们可以先不用管, 直接看最后一句, return new Launcher.ExtClassLoader(var1). 直接new了一个ExtClassLoader, 其中参数是var1, 代表的是ext扩展目录下的文件.
在ExtClassLoader(File[] var1)这个方法中, 这里第一步就是调用了父类的super构造方法. 而ExtClassLoader继承了谁呢? 我么你可以看到他继承了URLClassLoader.
而URLClassLoader是干什么用的呢? 其实联想一下大概能够猜数来, 这里有一些文件路径, 通过文件路径加载class类.
我们继续看调用的super(parent), 我们继续往下走, 就会看到一下内容
这里设置了ExtClassLoader的parent是谁? 注意看的话,我们发现, ExtClassLoader的parent类是null.
这就是传递过来的parent类加载器, 那么这里的parent类加载器为什么是null呢? 因为, ExtClassLoader的父类加载器是谁呢? 他是Bootstrap ClassLoader. 而BootStrap ClassLoader是C 的类加载器, 我们不能直接调用它, 所以, 设置为null.
其实, ExtClassLoader在初始化阶段就是调用了ExtClassLoader方法, 初始化了ExtClassLoader类
接下来,我们回到Launcher的构造方法, 看看Launcher接下来又做了什么?
可以看到, 接下来调了AppClassLoader的getAppClassLoader(var1), 这个方法. 需要注意一下的是var1这个参数. var1是谁呢? 向上看, 可以看到var1是ExtClassLoader.
这是AppClassLoader, 应用程序类加载器, 这个类是加载我们自己定义的类的类加载器. 他也是继承自URLClassLoader.
我们来看看getAppClassLoader(final ClassLoader var0)方法. 这个方法的参数就是上面传递过来的ExtClassLoader
这里第一句话就是获取当前项目的class 文件路径, 然后将其转换为URL. 并调用了Launcher.AppClassLoader(var1x, var0), 其中var1x是class类所在的路径集合, var0是扩展的类加载器ExtClassLoader, 接下来, 我们进入到这个方法里看一看
AppClassLoader直接调用了其父类的构造方法, 参数是class类路径集合, 和ExtClassLoader
最后, 我们看到, 将ExtClassLoader传递给了parent变量. 这是定义在ClassLoader中的属性, 而ClassLoader类是所有类加载器的父类. 因此, 我们也可以看到AppClassLoader的父类加载器是ExtClassLoader
同时, 我们也看到了, C 在启动JVM的时候, 调用了Launcher启动类, 这个启动类同时加载了ExtClassLoader和AppClassLoader.
public static void main(String[] args) { ClassLoader appClassLoader ClassLoader.getSystemClassLoader(); ClassLoader extClassLoader appClassLoader.getParent(); ClassLoader bootstrapClassLoad extClassLoader.getParent();
System.out.println( bootstrap class loader: bootstrapClassLoad); System.out.println( ext class loader extClassLoader); System.out.println( app class loader appClassLoader); }
通过这个demo, 我们也可以看出, appClassLoader的父类是extClassLoader, extClassLoader的父类是bootstrapClassLoader
输出结果:
bootstrap class loader: null ext class loader sun.misc.Launcher$ExtClassLoader 2a84aee7 app class loader sun.misc.Launcher$AppClassLoader 18b4aac2
JVM系列(二):JVM中类加载器相关知识笔记 JVM虚拟机运行的文件是class文件,它是由我们的Java程序编译后产生的文件。 类的加载:JVM虚拟机将指定的class文件读取到内存里,并解释运行该class文件里的Java程序的过程。 类的卸载:将某个class文件的运行时数据从JVM虚拟机中移除的过程。
【JVM深度解析】类加载与类加载器 你了解类加载机制吗?类加载器能说一下是什么吗?如何破坏双亲委派呢,多说几种?...不懂?一文带你了解类加载与类加载器
相关文章
- netty系列之:JVM中的Reference count原来netty中也有
- JDK中自带的JVM分析工具
- JDK、JRE、JVM之间的关系是什么样的?
- JVM内存模型和结构
- JavaSE高级:JVM重点内容探究
- 金九银十面试复习回顾及总结:算法 + 框架 +Redis+ 分布式 +JVM
- 程序员不会 jvm?骨灰级工程师:全等着被淘汰吧!这是必会技能!
- JVM的常用性能监控工具
- 康师傅JVM:本地方法栈(七)
- JVM知识总结-运行时区域划分
- 深入理解JVM虚拟机读书笔记——运行时数据区
- JVM_09 类加载与字节码技术(字节码指令3)
- 【JVM】JVM内存模型详解
- 02-JVM内存模型深度剖析与优化
- 面试准备——JVM相关
- 浅析Java中不使用的对象应赋值为null的深层理解:基本没必要的原因、JVM中局部变量表(运行时候的栈状态)和slot(运行时栈里的索引)的理解、Java的栈优化(重用栈索引节约内存空间)、GC的可达性分析算法-如何找到root树根(栈中引用的对象)、如何断开栈中引用与堆的联系(重写栈索引)
- 浅析JVM与Java内存区
- JVM内存参数详解以及配置调优
- version 1.5.2-04 of the jvm is not suitable for this product. version:1.6 or greater is required
- 横跨数据中心的JVM和Twitter的JDK
- JVM源码分析之javaagent原理完全解读--转
- eclipse指定JDK版本启动,解决version *** of the JVM is not suitable for this product.Version:*** 问题