JVM-类加载器子系统

JVM——类加载器子系统

类加载器子系统:负责从文件系统/网络中加载class文件

1. 类加载器分类

  • 启动类加载器Bootstrap ClassLoader
  • 扩展类加载器Extension ClassLoader
  • 系统类加载器AppClassLoader
  • 用户自定义加载器

除Bootstrap CLassLoader,其他类加载器都继承于ClassLoader

2. 双亲委派机制

  1. 一个类加载器收到了类加载请求,先把请求一层层向上面的父类加载器委托,直到Bootstrap ClassLoader
  2. 若父类可加载则直接返回,否则向下层子加载器分配任务
  3. 若分配至AppClassLoader也无法加载,抛出ClassNotFound异常

双亲委派机制作用

  • 避免类重复加载
  • 防止核心API被篡改

双亲委派机制

当执行main方法的时候,会出现如下问题:

在这里插入图片描述

可想而知,编译器根据包名一层一层的向上请求,在请求 bootstrap classloader加载器的时候, bootstrap classloader发现自己可以加载java.lang包下的String类,所以对类库中的String进行了加载,但是类库中的String类并没有main方法,所以抛出了上述异常。

判断两个类是否为同一个类

  • 完整类名相同
  • 加载该类的类加载器相同

打破双亲委派机制

自定义ClassLoader并且重写loadClass方法。为什么需要打破双亲委派机制:

在一个 Web 容器(如 Tomcat)中,可能同时部署了两个 Web 应用 A 和 B。

  • 问题:应用 A 需要 Spring 4.0,应用 B 需要 Spring 5.0。
  • 冲突:如果遵循双亲委派,共同的父类加载器加载了其中一个版本的 Spring,另一个应用就无法加载自己需要的版本了。
  • 解决:Tomcat 为每个 Web 应用创建了独立的 WebAppClassLoader,它会打破常规,优先加载应用自身目录下的类(WEB-INF/classes),从而实现不同应用间的类库隔离。

自定义类加载器

继承ClassLoader并且重写findClass方法loadClass 是负责协调委派流程的“管理者”,而 findClass 是负责去具体地方找字节码的“打工人”:

  • loadClass 是类加载的入口方法,它定义了加载的策略(即双亲委派机制)。

    • 默认行为:它会先检查类是否已加载,如果没有,就问父加载器要;父加载器要不到,才调用自己的 findClass
    • 重写它的目的:通常是为了打破双亲委派机制(例如 Tomcat 想要先加载自己的类,而不是先问父类)。
  • findClass 是 JDK 1.2 之后为了不破坏双亲委派而专门设计的扩展点

    • 默认行为:在基类 ClassLoader 中,它直接抛出 ClassNotFoundException
    • 重写它的目的:在遵循双亲委派机制的前提下,告诉加载器如何去非标准路径(如数据库、网络、加密文件)获取类的字节码。

JVM-类加载器子系统
http://example.com/2025/05/16/JVM-类加载器子系统/
作者
Kon4tsu
发布于
2025年5月16日
许可协议