Java 双亲委派机制:定义、原理、过程与设计目的

一、什么是双亲委派?

双亲委派是 Java 类加载器(ClassLoader)加载类时遵循的层级委派规则:当一个类加载器需要加载某个类时,它不会先自己尝试加载,而是先委托给“父加载器”去加载;只有当父加载器无法加载(找不到该类)时,子加载器才会自己尝试加载。

二、核心原理与运行过程

  1. 类加载器层级结构(自上而下)

Java 默认有 3 层核心类加载器,构成父子关系:

•	启动类加载器(Bootstrap ClassLoader):最顶层,由 C++ 实现,负责加载 JDK 核心类(如 java.lang.String,位于 JRE/lib/rt.jar 等核心 jar 包)。

•	扩展类加载器(Extension ClassLoader):启动类加载器的“子加载器”,负责加载 JDK 扩展类(如 javax 包下的类,位于 JRE/lib/ext 目录)。

•	应用类加载器(Application ClassLoader):扩展类加载器的“子加载器”,负责加载应用程序自身的类(如项目 classpath 下的类)。

注:这里的“父子”不是继承关系,而是通过“组合”实现的层级关联(子加载器持有父加载器的引用)。

  1. 运行过程(以加载 com.example.User 类为例)

    1. 应用类加载器收到加载 com.example.User 的请求,先委托给父加载器(扩展类加载器)。

    2. 扩展类加载器收到请求,不自己加载,继续委托给父加载器(启动类加载器)。

    3. 启动类加载器检查核心 jar 包,找不到 com.example.User,委托失败,将请求回传给扩展类加载器。

    4. 扩展类加载器检查扩展目录,找不到该类,委托失败,将请求回传给应用类加载器。

    5. 应用类加载器在项目 classpath 下找到 com.example.User,加载该类并返回。

三、为什么要设计双亲委派?

核心目的是保证类加载的安全性和唯一性:

1.	防止核心类被篡改:比如自定义一个 java.lang.String 类,由于双亲委派机制,会优先由启动类加载器加载 JDK 自带的 String,避免恶意类替换核心类。

2.	保证类的唯一性:同一个类(全限定名相同)只会被一个类加载器加载一次(父加载器加载过的类,子加载器无需重复加载),避免类重复加载导致的类型不一致问题(如两个 String 类对象无法互相转换)。

四、故事类比:公司“报销审批流程”

把类加载器比作公司的报销审批层级:

•	启动类加载器 = 董事长:负责审批“核心大额报销”(如公司战略采购费用)。

•	扩展类加载器 = 部门总监:负责审批“部门扩展费用”(如团队培训、设备升级)。

•	应用类加载器 = 项目经理:负责审批“项目日常小额报销”(如办公用品、差旅费)。

当项目经理(应用类加载器)收到员工的“差旅费报销申请”(加载 com.example.User 类):

1.	项目经理不直接批,先交给部门总监(扩展类加载器):“总监,您先看看这个报销能不能批?”

2.	总监也不直接批,交给董事长(启动类加载器):“董事长,您先过目~”

3.	董事长看了看:“这是项目日常差旅费,不属于核心大额报销,我批不了,回给总监。”

4.	总监看了看:“这不是部门扩展费用,我批不了,回给项目经理。”

5.	项目经理确认是项目日常开销,最终审批通过(加载类成功)。

这个流程的好处:

•	防止“员工伪造大额报销单”(对应防止篡改 JDK 核心类);

•	避免“同一笔费用被多个层级重复审批”(对应保证类的唯一性)。

总结:双亲委派通过“自上而下委托、自下而上加载”的规则,既保护了 JDK 核心类的安全,又保证了类加载的一致性,是 Java 类加载机制的核心设计。

更多推荐