如何破坏双亲委派模型

我们自己写的 java 源文件到最终运行,必须要经过编译和类加载两个阶段,编译的过程就是把.java 文件编译成.class 文件。

类加载的过程

类加载的过程,就是把 class 文件装载到 JVM 内存中,装载完成以后就会得到一个 Class对象,我们就可以使用 new 关键字来实例化这个对象。

而类的加载过程,需要涉及到类加载器。JVM 在运行的时候,会产生 3 个类加载器,这三个类加载器组成了一个层级关系每个类加载器分别去加载不同作用范围的 jar 包,比如:
  • Bootstrap ClassLoader,主要是负责 Java 核心类库的加载,也就是 %{JDK_HOME}\lib 下的 rt.jar、resources.jar 等
  • Extension ClassLoader,主要负责%{JDK_HOME}\lib\ext 目录下的 jar 包和 class文件
  • Application ClassLoader,主要负责当前应用里面的 classpath 下的所有 jar 包和类文件

除了系统自己提供的类加载器以外,还可以通过 ClassLoader 类实现自定义加载器,去满足一些特殊场景的需求。

双亲模型

而双亲模型,就是按照类加载器的层级关系,逐层进行委派。比如当需要加载一个 class 文件的时候,首先会把这个 class 的查询和加载委派给父加载器去执行,如果父加载器都无法加载,再尝试自己来加载这个 class。

不过,双亲委派并不是一个强制性的约束模型,我们可以通过一些方式去打破双亲委派模型。 这个打破的意思,就是类加载器可以加载不属于当前作用范围的类,实际上,JVM 本身就存在双亲委派被破坏的情况:
  • 第一种情况,双亲委派是在 JDK1.2 版本发布的,而类加载器和抽象类 ClassLoader 在JDK1.0 就已经存在了,用户可以通过重写 ClassLoader 里面的 loadClass()方法实现自定义类加载,JDK1.2 为了向前兼容,所以在设计的时候需要兼容 loadClass()重写的实现,导致双亲委派被破坏的情况。同时,为了避免后续再出现这样的问题,不在提倡重写 loadClass()方法,而是使用JDK1.2 中 ClassLoader 中提供了 findClass 方法来实现符合双亲委派规则的类加载逻辑。
  • 第二种情况,在这个类加载模型中,有可能存在顶层类加载器加载的类,需要调用用户类加载器实现的代码的情况。比如 java.jdbc.Driver 接口,它只是一个数据库驱动接口,这个接口是由启动类加载器加载的。

但是 java.jdbc.Driver 接口的实现是由各大数据库厂商来完成的,既然是自己实现的代码,就应该由应用类加载器来加载。于是就出现了启动类加载器加载的类要调用应用类加载器加载的实现。为了解决这个问题,在 JVM 中引入了线程上下文类加载器,它可以把原本需要启动类加载器加载的类,由应用类加载器进行加载。除此之外,像 Tomcat 容器,也存在破坏双亲委派的情况,来实现不同应用之间的资源隔离。

总结

如何破坏双亲委派模型,我知道有两种方式来破坏双亲委派模型:

  • 1. 第一种,集成 ClassLoader 抽象类,重写 loadClass 方法,在这个方法可以自定义要加载的类使用的类加载器。
  • 2. 第二种,使用线程上下文加载器,可以通过 java.lang.Thread 类的setContextClassLoader()方法来设置当前类使用的类加载器类型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值