类加载器的类型
一种是虚拟机底层来实现的,一种是使用Java来实现的。一共有以下几种:
- 启动类加载器(C语言编写):
- 启动类加载器BootstrapClassLoader负责加载%JAVA_HOME%中lib/ext文件下的jar包和class类文件
- BootstrapClassLoader是ExtClassLoader的上级, 在ExtClassLoder中有一个parent变量是BootstrapClassLoader,双亲委派则是通过该变量向上查找的
- 在Java程序中通过getClassLoader方法是获取不到的因为是使用C语言写的,当我们获取的时候会发现返回的只是null
- 扩展类加载器(ExtClassLoader使用Java代码实现):
- ExtClassLoader扩展类加载器,
- 负责加载%JAVA_HOME%中lib/ext文件下的jar包和class类文件,
- ExtClassLoader加载器是AppClassLoader的上级,同样AppClassLoader中也有一个parent变量是ExtClassLoader,双亲委派则是通过该变量向上查找的
- 应用类加载器(AppClassLoader使用Java代码实现):
- AppClassLoader是自定义加载器的父类,
- 负责加载classPath下的类文件,
- 平时引用的jar包以及我们自己写的类都是这个加载器进行加载的,同时AppClassLoader还是线程上下文加载器,如果想实现一个自定义加载器的话就继承(extends)ClassLoader来实现
可以使用Arthas 来查看当前应用的类加载器:
启动类加载器
- 启动类加载器BootstrapClassLoader
- 负责加载%JAVA_HOME%中lib/ext文件下的jar包
- 和class类文件BootstrapClassLoader是ExtClassLoader的上级, 在ExtClassLoder中有一个parent变量是BootstrapClassLoader,双亲委派则是通过该变量向上查找的
- 在Java程序中通过getClassLoader方法是获取不到的因为是使用C语言写的,当我们获取的时候会发现返回的只是null,例如:String类型是通过BootstrapClassLoader来加载的,当我们执行下面的代码的时候发现打印出的类加载器是一个null,所以当我们获取类加载器的时候获取到的是一个null 则表示当前类加载器使用的是BootstrapClassLoader
public class Test { public static void main(String[]args)throws IOException { ClassLoader classLoader = String.class.getClassLoader(); System.out.println(classLoader); System.in.read(); } }
如果我们新增了一些扩展的核心类我们希望启动类加载器帮我们加载这些扩展的核心类,可以通过以下方式:
-
将当前jar包放入jre/lib下之后启动类加载器会加载对应的jar包,不推荐这种方式,尽可能不要去更改JDK安装目录中的内容,因为Java虚拟机在加载的时候会对jar包的名称进行校验,名称必须符合一些规范,当不满足某些名称的规范的时候可能出现各种问题
-
使用参数进行扩展,推荐使用这种方式,使用-Xbootclasspath/a:jar包目录/jar包名进行扩展,例如:有一个项目,项目中只有一个类A,如下所示:
这里我们希望通过BootstrapClassLoader帮我们加载A类,前面说过类被初始化会调用静态代码块儿,也就是打印“A类被初始化了”这段字符串,利用maven 的package命令将当前项目进行打包:
找到当前jar包:
将jar包移动到要执行的目录,任意目录都可以,因为后面启动的路径是通过命令指定的:
接下来使用启动类加载器来加载这个jar包,这里准备类另外一个项目,这个项目中只有一个Demo1 的类,在idea 中选择配置虚拟机参数:
然后输入,-Xbootclasspath/a:jar包目录/jar包名称,-Xbootclasspath后面的那个a 字符代表添加的意思
使用以下方式调用A类,发现确实有打印到“A类被初始化了”这段字符:
Java中的类加载器
ExtClassLoader类加载器和AppClassLoader都是Java实现的类加载器,都继承了SecureClassLoader和URLClassLoader,SecureClassLoader使用证书机制提升了类加载器的安全性,URLClassLoader利用URL获取目录下或者指定的jar包进行加载,获取其字节码数据
扩展类加载器
- ExtClassLoader扩展类加载器,
- 负责加载%JAVA_HOME%中lib/ext文件下的jar包和class类文件,
- ExtClassLoader加载器是AppClassLoader的上级,同样AppClassLoader中也有一个parent变量是ExtClassLoader,双亲委派则是通过该变量向上查找的
与启动类加载器相同我们也可以利用以下方式来让扩展类加载器帮我们加载类:
- 放入jre/lib/ext下进行扩展,不推荐,尽可能不要去更改JDK安装目录中的内容
- 使用参数进行扩展,推荐,使用-Djava.ext.dirs=jar包目录进行扩展,这种方式会覆盖掉原始目录,可以用(windows)(macos/linux)追加上原始目录
同样在idea 中配置如下,这里的C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext是jdk的扩展目录,之后用分号分隔,输入自己要扩展的jar 包目录
应用程序类加载器
- AppClassLoader是自定义加载器的父类,
- 负责加载classPath下的类文件,
- 加载的是我们项目中的字节码文件以及项目以来的字节码文件,同时AppClassLoader还是线程上下文加载器,如果想实现一个自定义加载器的话就继承(extends)ClassLoader来实现
随便创建一个类,例如:
线程上下文类加载器
等待补充内容
osgi框架的类加载器
等待补充内容
JDK9以后的类加载器
去掉了扩展类加载器,新增平台类加载器根据jdk9中的模块化的概念进行加载,剩余部分等待后续补充