你了解 Java 的类加载器吗?

Sherwin.Wei Lv8

你了解 Java 的类加载器吗?

回答重点

Java 的类加载器(ClassLoader)是 JVM 中用于动态加载类文件的组件。它将 .class 文件中的字节码加载到内存中,并将其转换为 Class 对象,以供 JVM 执行。

类加载器的作用

  • 动态加载类:在运行时根据需要加载类,而不是在编译时加载所有类。
  • 隔离不同的类命名空间:通过不同的类加载器,可以隔离同名类,使得它们不会相互冲突。

扩展知识

类加载器的层次结构

JDK8 的时候一共有三种类加载器:

1)启动类加载器(Bootstrap ClassLoader),它是属于虚拟机自身的一部分,用 C++ 实现的(JDK9 后用 java 实现),主要负责加载\lib目录中或被 -Xbootclasspath 指定的路径中的并且文件名是被虚拟机识别的文件,它是所有类加载器的父亲。

2)扩展类加载器(Extension ClassLoader),它是 Java 实现的,独立于虚拟机,主要负责加载\lib\ext目录中或被 java.ext.dirs 系统变量所指定的路径的类库。

3)应用程序类加载器(Application ClassLoader),它是 Java 实现的,独立于虚拟机。主要负责加载用户类路径(classPath)上的类库,如果我们没有实现自定义的类加载器那这个加载器就是我们程序中的默认加载器。

在 JDK9 之后,类加载器进行了一些修改,主要是因为 JDK9 引入了模块化,即 Jigsaw,原来的 rt.jar、tool.jar 等都被拆成了数十个 jmod 文件,已满足可扩展需求,无需保留 \lib\ext ,所以扩展类加载器也被重命名为平台类加载器(PlatformClassLoader),主要加载被 module-info.java 中定义的类。

且双亲委派的路径也做了一定的变化:

企业微信截图_356498bd-8c60-4b0e-b599-999b047d4376.png

在平台和应用类加载器受到加载请求时,会先判断该类是否属于一个系统模块,如果属于则委派给对应的模块类加载器加载,反之才委派给父类加载器。

JDK9 之后类加载器负责模块(图来自网络):

企业微信截图_c43e2b11-4eb9-4a0f-b07b-4326341a1b6e.png

企业微信截图_a2c32e43-ee8a-42cc-a07d-52ccc862fc85.png

企业微信截图_eab6eed5-fc23-462b-9e0d-6dd3c2131ec7.png

Java 的类加载过程

双亲委派模型

在类加载过程中,类加载器会优先将加载请求委托给父类加载器,只有当父类加载器无法加载时,才会由当前加载器尝试加载。这种机制保证了 Java 核心类库的安全性,避免核心类库被篡改或替换。

自定义类加载器的实现

通过继承 ClassLoader 类并重写 findClass() 方法,可以自定义类加载器。自定义类加载器常用于应用服务器、插件系统等场景,允许不同模块使用各自的类加载器隔离同名类。

1
2
3
4
5
6
7
8
public class CustomClassLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// 自定义类加载逻辑
byte[] classData = getClassData(name);
return defineClass(name, classData, 0, classData.length);
}
}

常见的类加载器应用场景

  • Web 容器:如 Tomcat,每个 Web 应用都有自己的类加载器,确保各应用相互隔离,防止类冲突。
  • OSGi:使用类加载器动态加载和卸载模块,实现灵活的模块化架构。
  • 热加载:开发环境中使用的热部署技术(如 JRebel)通过自定义类加载器支持类的动态重载。
Comments