双亲委派模型是 Java 类加载器的一种设计模式,它定义了类加载器之间的层次结构关系以及类是如何被加载的。这种模型确保了 Java 核心库的稳定性和安全性,同时也提供了灵活性来扩展类加载的过程。
双亲委派模型概述
双亲委派模型中,每一个类加载器都有一个父类加载器。类加载请求总是首先委托给父类加载器去完成,只有当父类加载器无法完成这个请求时,子类加载器才会尝试自己去加载。
Java 中的类加载器主要有三种类型:
- 启动类加载器 (Bootstrap ClassLoader):这是最顶层的类加载器,它用来加载 Java 的核心库(如
rt.jar
),并且是 C++ 实现的,没有父类加载器。 - 扩展类加载器 (Extension ClassLoader):它的父类加载器是启动类加载器,它用来加载扩展目录 (
lib/ext
或者由-Djava.ext.dirs
指定的路径) 中的 jar 文件。 - 应用程序类加载器 (Application ClassLoader):它的父类加载器是扩展类加载器,它是默认的类加载器,用来加载 classpath 中指定的类。
加载流程
当应用程序需要加载一个类时,加载流程如下:
- 首先检查该类是否已经被加载过。如果已经加载过,则直接返回已加载的类。
- 如果未加载,那么应用程序类加载器会委托给父类加载器——扩展类加载器。
- 扩展类加载器同样会委托给其父类加载器——启动类加载器。
- 如果启动类加载器能够找到并加载该类,那么就返回该类;否则启动类加载器会把加载请求回退给扩展类加载器。
- 扩展类加载器尝试加载,如果不能加载则再次回退给应用程序类加载器。
- 最后,如果应用程序类加载器也不能加载,那么就会抛出
ClassNotFoundException
。
为什么采用双亲委派机制
-
保证核心库的安全性:
- 双亲委派模型可以避免用户自定义的类加载器加载核心库的类,从而防止恶意篡改核心库的行为。
-
避免类重复加载:
- 通过委派机制,类加载器之间形成了层次化的结构,这样可以避免同一个类被多次加载到同一个 JVM 中。
-
便于资源隔离:
- 不同的应用程序可以使用不同的类加载器,这样可以使得不同应用程序之间互不影响,有利于资源的隔离。
-
灵活的扩展:
- 用户可以自定义类加载器,通过继承
java.lang.ClassLoader
类来实现特定需求的类加载逻辑,同时保持核心库的稳定性。
- 用户可以自定义类加载器,通过继承
-
提高性能:
- 经常使用的类可以被缓存起来,下次使用时可以直接从缓存中获取,而不需要重新加载。
总之,双亲委派模型为 Java 类加载机制提供了一种高效且安全的解决方案,它不仅增强了 Java 系统的稳定性,也方便了开发人员对类加载过程的定制化。