扩展类加载器默认负责加载javax.*等扩展类,但不主动发起加载,而是由AppClassLoader委派后才介入;它从JAVA_HOME/jre/lib/ext或java.ext.dirs路径加载,JDK9+由平台类加载器替代。

Java 类加载器通过双亲委派机制加载扩展类,并不是由扩展类加载器“主动发起”加载,而是遵循“先向上委托、再向下尝试”的固定流程。关键在于:扩展类(如 javax.* 下的类)**默认由扩展类加载器(Extension ClassLoader)加载**,但它本身不直接启动加载动作,而是被上层的应用类加载器触发、经委派后才介入。
扩展类加载器的职责范围
扩展类加载器负责加载以下位置的类:
-
JAVA_HOME/jre/lib/ext目录下的所有 JAR 包(JDK 8 及之前) - 由系统属性
java.ext.dirs指定的路径中的 JAR 或 class 文件 - 部分 JDK 自带的扩展 API,例如
javax.crypto.*、javax.xml.*等(非核心但非应用自定义)
双亲委派中它如何被调用
当代码中首次引用一个扩展类(比如 javax.crypto.Cipher)时,实际触发的是应用程序类加载器(AppClassLoader)。此时流程如下:
- AppClassLoader 收到加载请求,不直接查找,而是调用
getParent()向上委派给 ExtClassLoader - ExtClassLoader 接收到委派后,检查自己负责的路径(如
ext目录)是否存在对应类的字节码 - 若存在,读取并定义为
Class对象,完成加载;若不存在,继续向上委派给 BootstrapClassLoader - Bootstrap 不处理
javax.*类(它只认java.*核心类),返回失败,控制权回到 ExtClassLoader —— 此时它已确认该类应由自己加载
验证它是否生效的简单方式
可通过打印类加载器链直观确认:
System.out.println(Class.forName("javax.crypto.Cipher").getClassLoader()); // 输出 ExtClassLoader 实例
System.out.println(Class.forName("java.lang.String").getClassLoader()); // 输出 null(Bootstrap 加载)
System.out.println(getClass().getClassLoader()); // 输出 AppClassLoader
注意:JDK 9+ 中扩展类加载器已被平台类加载器(PlatformClassLoader)替代,但委派逻辑不变,仍承接原 ExtClassLoader 的职责。
为什么不能跳过委派直接让 AppClassLoader 加载扩展类
这是双亲委派的核心安全设计:
- 防止用户自定义同名类(如伪造
javax.net.ssl.SSLContext)覆盖 JDK 扩展功能 - 确保所有
javax.*类由可信的、预置的加载器加载,避免类版本冲突或恶意替换 - 保持类的唯一性:同一个全限定名的类,在 JVM 中只会被一个类加载器定义一次
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











