如何打破双亲委派模型?打破双亲委派模型示例?什么是双亲委派模型?

什么是双亲委派模型?
双亲委派模型:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上,因此,所有的类加载请求最终都应该被传递到顶层的启动类加载器中,只有当父加载器在它的搜索范围中没有找到所需的类时,即无法完成该加载,子加载器才会尝试自己去加载该类。

使用双亲委派模型来组织类加载器之间的关系,有一个很明显的好处,就是Java类随着它的类加载器(说白了,就是它所在的目录)一起具备了一种带有优先级的层次关系,这对于保证Java程序的稳定运作很重要。例如,类java.lang.Object类存放在JDK\jre\lib下的rt.jar之中,因此无论是哪个类加载器要加载此类,最终都会委派给启动类加载器进行加载,这边保证了Object类在程序中的各种类加载器中都是同一个类。

在这里插入图片描述
在这里插入图片描述
为什么要打破双亲委派模型?

举一个最常见的例子:我们常用数据库驱动Driver接口,Driver定义在jdk当中,当其实现却是各个数据库服务商,例如,mysql的MYSQL CONNECROR,所有这就有个问题,DriverManger要加载各个Driver接口实现类,然后进行管理,但是DriverManager是由启动类加载器进行加载的,而这个启动类加载器默认值加载JAVA_HOME下面的lib,但我们真正要加载的是各个实现类,需要有系统类加载器进行加载,这个时候就需要启动类加载器委托系统类加载器去加载Driver实现类,从而破坏了双亲委派。

最常见的打破双亲委派模型示例:
JNDI 通过引入线程上下文类加载器,可以在 Thread.setContextClassLoader 方法设置,默认是应用程序类加载器,来加载 SPI 的代码。有了线程上下文类加载器,就可以完成父类加载器请求子类加载器完成类加载的行为。打破的原因,是为了 JNDI 服务的类加载器是启动器类加载,为了完成高级类加载器请求子类加载器(即上文中的线程上下文加载器)加载类。
Tomcat,应用的类加载器优先自行加载应用目录下的 class,并不是先委派给父加载器,加载不了才委派给父加载器。打破的目的是为了完成应用间的类隔离。
OSGi,实现模块化热部署,为每个模块都自定义了类加载器,需要更换模块时,模块与类加载器一起更换。其类加载的过程中,有平级的类加载器加载行为。打破的原因是为了实现模块热替换。
JDK 9,Extension ClassLoader 被 Platform ClassLoader 取代,当平台及应用程序类加载器收到类加载请求,在委派给父加载器加载前,要先判断该类是否能够归属到某一个系统模块中,如果可以找到这样的归属关系,就要优先委派给负责那个模块的加载器完成加载。打破的原因,是为了添加模块化的特性。

打破双亲委派模型的方式:
1.继承ClassLoader这样一个抽象类,然后重写里面loadClass方法,在这个里面可以自定义要加载的类使用的类加载器。
2.使用线程的上下文加载器,可以通过java.lang.Thread类的setContextClassLoader()这个方法去设置当前类加载器的一个类型。

总结:
1.java 的类加载,就是获取.class文件的二进制字节码数组并加载到 JVM 的方法区,并在 JVM 的堆区建立一个用来封装 java 类相关的数据和方法的java.lang.Class对象实例。
2.java默认有的类加载器有三个,启动类加载器(BootstrapClassLoader),扩展类加载器(ExtClassLoader),应用程序类加载器(也叫系统类加载器)(AppClassLoader)。类加载器之间存在父子关系,这种关系不是继承关系,是组合关系。如果parent=null,则它的父级就是启动类加载器。启动类加载器无法被java程序直接引用。
3.双亲委派就是类加载器之间的层级关系,加载类的过程是一个递归调用的过程,首先一层一层向上委托父类加载器加载,直到到达最顶层启动类加载器,启动类加载器无法加载时,再一层一层向下委托给子类加载器加载。
4.双亲委派的目的主要是为了保证java官方的类库<JAVA_HOME>\lib和扩展类库<JAVA_HOME>\lib\ext的加载安全性,不会被开发者覆盖。

### Java 类加载器双亲委派机制的工作原理 Java 中的类加载器采用一种称为双亲委派模型的机制来加载类文件。在这个模型中,每当一个类加载请求发生时,该请求并不会立即由当前类加载器处理,而是先传递给父类加载器进行处理;只有当父类加载器无法完成加载任务时,才会尝试自行加载。 具体来说,在接收到一个类加载请求之后: - 首先会检查所要加载的类是否已经被加载过; - 如果尚未加载,则继续向上委托至父类加载器执行相同的操作; - 这一过程一直持续到最顶层的引导类加载器为止[^1]。 一旦某个上级类加载器能够成功找到并加载所需的类,则整个查找流程结束,并返回已加载好的 Class 对象实例给最初发起请求的地方使用。这样的设计不仅简化了 JVM 的内部结构,还增强了系统的安全性与稳定性,因为核心 API 总是由信任度最高的引导类加载器负责加载,防止恶意代码替换标准库中的重要组件[^3]。 对于开发者而言,理解这一机制有助于更好地管理项目中的依赖关系以及应对可能出现的各种异常情况,比如 `ClassNotFoundException` 或者 `NoClassDefFoundError` 等问题[^2]。 ```java // 自定义类加载器示例 public class CustomClassLoader extends ClassLoader { @Override protected Class<?> findClass(String name) throws ClassNotFoundException { byte[] b = loadClassData(name); return defineClass(name, b, 0, b.length); } private byte[] loadClassData(String className){ // 实现读取字节码逻辑... return null; } } ``` #### 打破双亲委派机制的方式 为了满足特定应用场景的需求,有时也需要打破默认的双亲委派模式。这通常涉及到创建自定义类加载器,并重写 `findClass()` 方法而不是覆盖 `loadClass()` ,后者已经实现了完整的双亲委派算法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值