双亲委派模型

双亲委派模型

双亲委派模型(Parent Delegation Model)是 Java 类加载器(ClassLoader)的核心设计模式,用于​保证类加载的安全性和唯一性​,避免类重复加载和核心类被篡改。

一、核心原理

当一个类加载器收到类加载请求时,它不会立即自己加载,而是​先委派给父类加载器​,逐层向上传递请求;只有当父类加载器无法加载该类(在其搜索范围内找不到)时,子类加载器才会尝试自己加载。

简单来说:​先找爹,爹不行,自己上​。

二、类加载器层级结构

Java 中的类加载器按层级从上到下分为:

  1. 启动类加载器(Bootstrap ClassLoader)

    • 最顶层,由 C++ 实现(非 Java 类),负责加载$JAVA_HOME/jre/lib/rt.jar​(核心类库,如java.lang.String​)。

    • 无父类加载器,也无法通过 Java 代码直接引用。

  2. 扩展类加载器(Extension ClassLoader)

    • 父类是启动类加载器,负责加载$JAVA_HOME/jre/lib/ext/*.jar​(扩展类库)。

    • 由sun.misc.Launcher$ExtClassLoader​实现。

  3. 应用程序类加载器(Application ClassLoader)

    • 父类是扩展类加载器,负责加载用户类路径(ClassPath​)下的类(项目代码、第三方依赖)。

    • 由sun.misc.Launcher$AppClassLoader​实现,也是默认的系统类加载器。

  4. 自定义类加载器(Custom ClassLoader)

    • 开发者继承java.lang.ClassLoader​实现,用于加载自定义路径的类(如 Tomcat 的 WebAppClassLoader)。

三、工作流程

以加载com.example.Test​类为例:

  1. 应用程序类加载器收到请求,先委派给父类​扩展类加载器​。

  2. 扩展类加载器再委派给父类​启动类加载器​。

  3. 启动类加载器检查核心类库,发现没有com.example.Test​,返回 “无法加载”。

  4. 扩展类加载器检查扩展类库,也没有,返回 “无法加载”。

  5. 应用程序类加载器在ClassPath​下查找并加载com.example.Test​类。

四、优势

  1. ​安全性​:核心类(如java.lang.String​)只能由启动类加载器加载,避免用户自定义同名类篡改核心 API(防止 “String 类被替换” 等安全问题)。

  2. ​唯一性​:同一个类只会被加载一次(由最顶层的类加载器加载),保证类的全局唯一性(类的唯一性 = ClassLoader + 全限定类名)。

  3. 层级隔离:不同层级的类加载器负责不同范围的类,避免类冲突。

五、打破双亲委派模型的场景

并非所有场景都严格遵循双亲委派,以下情况会 “反向委派” 或直接加载:

  1. SPI 机制(Service Provider Interface)例如 JDBC 驱动(java.sql.Driver​):核心类Driver​由启动类加载器加载,但具体驱动实现(如 MySQL 驱动)在ClassPath​下,需由应用程序类加载器加载 → 启动类加载器会委派子类加载器加载(线程上下文类加载器实现)。

  2. Tomcat 等容器Tomcat 为每个 Web 应用创建独立的类加载器(WebAppClassLoader),优先加载应用内的类(而非委派父类),避免不同应用的类冲突。

  3. 热部署 / 动态加载自定义类加载器需实时加载新类,可能绕过双亲委派直接加载。

CI/CD 持续集成与持续交付基础知识 2026-07-19