系列文章目录
1:JVM核心知识
1.2:类加载器
前言
本系列主要针对想进一步进阶Java的开发者,本文介绍Java的类加载器。
一、Java类加载器是什么?
Java类加载器(Java Classloader)是Java运行时环境(Java Runtime Environment)的一部分,负责动态加载Java类到Java虚拟机的内存空间中,用于加载系统、网络或者其他来源的类文件。Java源代码通过javac编译器编译成类文件,然后JVM来执行类文件中的字节码来执行程序。
二、类的生命周期
1. 加载(Loading):找 Class 文件
2. 验证(Verification):验证格式、依赖
3. 准备(Preparation):静态字段、方法表
4. 解析(Resolution):符号解析为引用
5. 初始化(Initialization):构造器、静态变 量赋值、静态代码块
6. 使用(Using)
7. 卸载(Unloading)
三、类加载器三种类型
1. 启动类加载器(BootstrapClassLoader)
启动类加载器主要加载Object,String,JDK安装目录下rt.jar的类。
2. 扩展类加载器(ExtClassLoader)
作为启动类加载器补充,比如JDK,JRE中指定目录下放的jar包。
3. 应用类加载器(AppClassLoader)
负责加载自己编写的,运行时指定classpath中的类。
Q:为什么需要这三种类加载器,按理说只要启动类加载器和应用类加载器不就行了吗?
如果一个JDK要启动很多应用程序,这些应用程序又有共同的依赖,那么把这些共性依赖从应用类加载器提出,放入扩展类加载器中,如果放入启动类加载器,那么对个别应用程序来说就多了一层不必要的包,如果放在应用类加载器,每个应用程序加载都要单独指定一下,很麻烦。
四、类加载器三个特点:
1. 双亲委托
首先我们要知道类加载器的层级
Q:什么是双亲委托?
把自己要加载的类委托给双亲来探测是否加载过,如果加载过,双亲会给子类加载器返回一个引用,如果没有加载过,子类加载器会自己加载。需要注意的是,这个探测要一直往上,也就是说:
如果子类的父亲没有加载过,就会去找子类的爷爷,一直到根加载器。
Q: 为什么需要双亲委托?
如果没有双亲委托,将会加载大量重复的类,造成资源的浪费。
2. 负责依赖
如果加载某个类时,需要加载其他类,那么当前类加载器也会把其他类加载了。
这很好理解,因为我们都遇见过在启动一个Java应用的时候出现找不到类的情况,如果没有负责依赖,我们将寸步难行。
3. 缓存加载
默认情况下所有类都会只加载一次,当类加载完成后,会缓存在内存之中。
Q:学习类加载器有什么作用?
当你发现一些jar包加载不上时可以用debug的方式去找类加载器,查看里面ucp的paths,可以排查当前应用加载的jar包。
这里放一个类加载器实例,仅供参考:
五:怎么指定特定jar包到类加载器中:
1、放到 JDK 的 lib/ext 下,或者 -Djava.ext.dirs
2、 java-cp/classpath 或者 class 文件放到当前路径
3、自定义 ClassLoader 加载
4、拿到当前执行类的 ClassLoader,反射调用 addUrl 方法添加 Jar 或路径(JDK9 无效)
总结
以上就是今天要讲的内容,本文介绍了Java类加载器的内容,这对于排查找不到jar包的问题是非常有用的,接下来我们将介绍JVM的内存模型,敬请期待。