双亲委派机制

双亲委派机制

  1. 官方定义

    • 双亲委派机制是 Java 虚拟机(JVM)类加载机制中的一种层次化的类加载策略。当一个类加载器(ClassLoader)收到类加载请求时,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器。只有当父类加载器无法完成加载任务(即它在自己的搜索范围内找不到对应的类)时,子加载器才会尝试自己去加载。这种机制就像一个孩子(子加载器)遇到问题先问父母(父加载器),只有父母解决不了才自己动手。

  2. 主要特点

    • 层次化的加载顺序:类加载器之间形成了一种层次关系,如启动类加载器(Bootstrap ClassLoader)处于最顶层,然后是扩展类加载器(Extension ClassLoader),再是应用程序类加载器(Application ClassLoader)等。加载请求会按照这个层次结构自顶向下传递,保证了类加载的顺序性和系统性。

    • 保证类的唯一性:通过双亲委派机制,同一个类只会被加载一次。因为在层次结构中,父类加载器加载过的类,子类加载器不会再重复加载。例如,如果启动类加载器已经加载了java.lang.String类,那么应用程序类加载器就不会再加载这个类,从而避免了类的重复加载和可能导致的类型冲突。

  3. 主要应用场景和用途

    • 保证核心类库的安全性和一致性:在 Java 运行环境中,核心类库(如java.lang包中的类)是由启动类加载器加载的。通过双亲委派机制,这些核心类库能够优先加载,并且不会被其他恶意或错误的同名类所替代。例如,防止用户自定义的一个名为java.lang.String的类被错误加载,从而保证了 Java 程序运行的基本安全和核心功能的一致性。

    • 类加载的分工协作:不同层次的类加载器负责加载不同范围的类,实现了一种分工。启动类加载器负责加载 Java 的核心类库,扩展类加载器加载 Java 扩展库,应用程序类加载器加载应用程序自身的类。这种分工使得类加载过程更加有序,也便于管理和维护。

  4. 与主流技术的相似之处和区别

    • 与自定义类加载策略的相似与区别:

      • 相似之处:都是用于控制类的加载过程。自定义类加载策略可以根据特定的需求灵活地加载类,而双亲委派机制本身也是一种类加载策略。

      • 区别:双亲委派机制是 Java 默认的、标准化的类加载方式,它具有固定的层次结构和加载顺序,主要目的是保证类加载的安全性和一致性。自定义类加载策略则可以打破这种常规的加载顺序,用于一些特殊的场景,如热部署(在不重启应用程序的情况下更新某些类)、加载加密的类文件等。但如果自定义类加载策略设计不当,可能会破坏类加载的安全性和正常秩序。

    • 与其他编程语言的模块加载系统的相似与区别:

      • 相似之处:与一些编程语言(如 Python 的模块加载系统)类似,都有一个用于管理和加载代码单元(类或模块)的机制,目的都是为了正确地组织和加载代码,以便程序能够正常运行。

      • 区别:Java 的双亲委派机制具有更严格的层次结构和安全性保障。在 Python 中,模块加载相对更加灵活,没有像 Java 这样严格的双亲委派式的层次结构,它更侧重于模块的查找路径和命名空间的管理,虽然也有一定的顺序来查找模块,但不像 Java 双亲委派机制那样形成一个严格的、自顶向下的层次加载体系。

双亲委派机制--再理解

当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载其中,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的Class),子类加载器才会尝试自己去加载。

采用双亲委派的一个好处是比如加载位于 rt.jar 包中的类 java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类

加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同样一个 Object 对象

启动类加载器,加载JAVA_HOME/lib;

扩展类加载器,加载JAVA_HOME/lib/ext目录中;

应用程序类加载器,负责用户路径上的类库;

什么时候用到

双亲委派机制在很多情况下都会被用到,不仅仅是在使用 import 语句时。

例如,当我们通过 new 关键字创建一个对象时,JVM 会去加载对应的类,此时就会遵循双亲委派机制。

假设我们自定义了一个名为 java.lang.String 的类,当程序尝试创建这个自定义类的对象时,双亲委派机制就会发挥作用。首先,应用程序类加载器不会直接加载这个类,而是将加载请求委派给它的父类加载器扩展类加载器。扩展类加载器也不会加载,继续将请求委派给启动类加载器。由于启动类加载器能够找到并加载 Java 核心库中的 java.lang.String 类,所以就不会使用我们自定义的同名类,从而保证了 Java 核心类的权威性和一致性。

又如,当一个类的静态方法被调用时,JVM 同样会按照双亲委派机制去加载该类。

总之,只要涉及到类的加载,JVM 都会遵循双亲委派机制,以确保类的加载安全和正确,这是 JVM 类加载机制的一个重要原则和保障。

JVM如何知道所需的类

虚拟机设计团队把加载动作放到 JVM 外部实现,以便让应用程序决定如何获取所需的类, JVM 提供了 3 种类加载器:

启动类加载器 (Bootstrap ClassLoader)

(根加载器)

负责加载 JAVA_HOME\lib 目录中的, 或通过-Xbootclasspath 参数指定路径中的, 且被虚拟机认可(按文件名识别,如 rt.jar) 的类。

扩展类加载器 (Extension ClassLoader)

负责加载 JAVA_HOME\lib\ext 目录中的,或通过 java.ext.dirs 系统变量指定路径中的类库。

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

(系统加载器)

负责加载用户路径(classpath)上的类库。JVM 通过双亲委派模型进行类的加载, 当然我们也可以通过继承 java.lang.ClassLoader实现自定义的类加载器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值