JVM的双亲委派模型

引言

Java类加载机制中的双亲委派模型通过层层委托保证了核心类加载器与应用类加载器之间的职责分离和加载安全性,但其单向的委托关系也带来了一些局限性。尤其是在核心类库需要访问或实例化由应用类加载器加载的类时,双亲委派模型无法满足需求,导致系统类无法直接调用应用类中的实现。为解决这一问题,Java采用了线程上下文类加载器(Context ClassLoader)机制,打破了传统双亲委派的限制,使核心类库能够通过当前线程的上下文类加载器访问应用层的扩展类。典型应用如JDBC中的DriverManager通过服务提供者接口(SPI)机制,利用上下文类加载器动态加载数据库驱动,实现了灵活可扩展的设计。本文将围绕双亲委派模型的不足及其被打破的原因,深入探讨SPI机制及线程上下文类加载器的作用与实现原理。

1. 什么是双亲委派模型?

https://zhuanlan.zhihu.com/p/612318527https://zhuanlan.zhihu.com/p/612318527

2. 为什么要打破双亲委派模型?

检查类是否加载的委托过程是单向的,这个方式虽然从结构上说比较清晰,使各个ClassLoader的职责非常明确,但是同时会带来一个问题,即顶层的ClassLoader无法访问底层的ClassLoader所加载的类。

通常情况下,启动类加载器中的类为系统核心类,包括一些重要的系统接口,而在应用类加载器中,为应用类。按照这种模式,应用类访问系统类自然是没有问题,但是系统类访问应用类就会出现问题。比如在系统类中提供了一个接口,该接口需要在应用类中得以实现,该接口还绑定一个工厂方法,用于创建该接口的实例,而接口和工厂方法都在启动类加载器中。这时,就会出现该工厂方法无法创建由应用类加载器加载的应用实例的问题。

3. SPI是如何打破双亲委派机制的?

由于双亲委派模型的限制,父加载器无法访问由子加载器加载的类,所以核心类库无法直接访问这些SPI实现类。当核心类库需要调用SPI实现时,它会通过Thread.currentThread().getContextClassLoader()获取当前线程的上下文类加载器,从而可以访问到应用层的实现类。

DriverManager是JDBC里管理和注册不同数据库Driver的工具类。在使用Java JDBC进行数据库编程时,我们引入驱动包之后,直接使用Connection connection = DriverManager.getConnection(url,user,password);便可以成功获得数据库连接。

  • 启动类加载器加载DriverManager。
  • DriverManager.getConnection时,通过SPI机制加载jar包中的mysql驱动。
  • SPI中利用了线程上下文类加载器(应用程序类加载器)去加载类并创建对象。

4. SPI机制

  1. 需要先定义一个接口,作为扩展的标准。
  2. 在 classpath 目录下创建 META-INF/service 文件目录。
  3. 在这个目录下,创建以接口的全限定名命名的配置文件,文件内容是这个接口的实现类。
  4. 在应用程序里面,使用 ServiceLoad.load(),就可以根据接口名称找到 classpath 所有的扩展类。

感谢您的阅读!如果文章中有任何问题或不足之处,欢迎及时指出,您的反馈将帮助我不断改进与完善。期待与您共同探讨技术,共同进步!

### 回答1: 我不认为JVM可以“打破”双亲委派模型JVM使用双亲委派模型是为了保证类的加载和安全性,这是JVM的基本设计原则之一。 在双亲委派模型中,当一个类被加载时,首先会委托其父类加载器尝试加载该类。如果父类加载器无法加载该类,则会将该请求传递给其父类加载器的父类加载器,直到最终传递到启动类加载器。如果启动类加载器也无法加载该类,则会抛出ClassNotFoundException异常。 这种模型的好处是可以防止类的重复加载,并且可以保证类的安全性,因为只有在受信任的类加载器中加载的类才能访问受信任的资源。如果JVM打破了这种模型,可能会导致类的重复加载和不安全的类访问,从而破坏JVM的基本设计原则。 虽然JVM不能打破双亲委派模型,但是它提供了一些机制来绕过该模型。例如,可以使用Java的反射机制或者自定义类加载器来加载类,但是这些机制都需要开发者自己负责类的加载和安全性,因此需要谨慎使用。 ### 回答2: JVM双亲委派模型是一种类加载机制,用于保证Java程序的安全性和稳定性。在双亲委派模型中,JVM首先会查找并加载自定义类加载器的类,如果找不到,才会向上一级的父类加载器请求加载。这种模型的好处是可以避免类重复加载和类冲突,确保程序的运行稳定性。 但有时候,我们可能需要打破双亲委派模型,以满足特定的需求。下面是一些打破双亲委派模型的方式: 1. 自定义类加载器:可以自己编写一个类加载器,并重写其中的加载类的逻辑。这样就可以绕过父类加载器,直接加载自定义的类。 2. 加载本地库:JVM的类加载器无法加载本地库,因此可以通过JNI(Java Native Interface)来打破双亲委派模型,直接加载本地库。 3. 使用反射技术:通过反射,可以调用私有的加载类方法,从而绕过双亲委派模型,加载特定的类。 4. 使用SPI机制:在Java标准库中,有一些接口通过SPI(Service Provider Interface)机制提供了灵活的类加载方式,可以通过实现自己的SPI来打破双亲委派模型。 需要注意的是,打破双亲委派模型可能会导致类的重复加载和类冲突,引发程序的运行问题。因此,在使用这些方法时,需要谨慎考虑,确保安全性和稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值