双亲委派模型

模型图

image.png

破坏双亲委派模型有两种方式

一、引入线程上下文类加载器

Java 提供了很多服务提供者接口(Service Provider Interface,SPI),允许第三方为这些接口提供实现。常见的 SPI 有 JDBC、JCE、JNDI、JAXP 和 JBI 等。
这些 SPI 的接口由 Java 核心库来提供,而这些 SPI 的实现代码则是作为 Java 应用所依赖的 jar 包被包含进类路径(CLASSPATH)里。SPI接口中的代码经常需要加载具体的实现类。那么问题来了,SPI的接口是Java核心库的一部分,是由引导类加载器来加载的;SPI的实现类是由系统类加载器来加载的。引导类加载器是无法找到 SPI 的实现类的,因为依照双亲委派模型,BootstrapClassloader无法委派AppClassLoader来加载类。
而线程上下文类加载器破坏了双亲委派模型,可以在执行线程中抛弃双亲委派加载链模式,使程序可以逆向使用类加载器。

刚开始有个疑问就是:既然你是SPI接口,那你提供接口就好了,为什么要加载具体的实现类?

发现JDK中确实有一些这种情况:

1、接口想提供一个默认的实现。

如 JAXP 中的 javax.xml.parsers.DocumentBuilderFactory类中的 newInstance()方法用来生成一个新的 DocumentBuilderFactory的实例。这里的实例的真正的类是继承自 javax.xml.parsers.DocumentBuilderFactory,由 SPI 的实现所提供的。如在 Apache Xerces 中,实现的类是 org.apache.xerces.jaxp.DocumentBuilderFactoryImpl。而问题在于,SPI 的接口是 Java 核心库的一部分,是由引导类加载器来加载的;SPI 实现的 Java 类一般是由系统类加载器来加载的。引导类加载器是无法找到 SPI 的实现类的,因为它只加载 Java 的核心库。它也不能代理给系统类加载器,因为它是系统类加载器的祖先类加载器。


image.png

image.png

可以发现DocumentBuilderFactoryImpl本来是存在于org.apache.xerces.jaxp这个包里的,是第三方类库,使用的加载器是AppClassLoader,后来JDK8把他移到了rt.jar内,应该也是为了不破坏双亲委派模型。

2、JDBC java.sql.DriverManager统一注册实现类和获取连接

真正理解线程上下文类加载器(多案例分析)
DruidDriver.registerDriver -> DriverManager.registerDriver -> DriverManager.loadInitialDrivers.AccessController.doPrivileged -> ServiceLoader.load -> driversIterator.next

image.png

根据JDBC加载源码进行断点发现DriverManager.loadInitialDrivers初始化时,会在DriverManager中加载com.alibaba.druid.proxy.DruidDriver,此时就是利用的线程上下文类加载器来实现
image.png

二、自定义ClassLoader

  1. 如果不想不破坏双亲委派模型,只要去重写findClass方法
  2. 如果想要去破坏双亲委派模型,需要去重写loadClass方法

破坏双亲委派模型和自定义自己的类加载器

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容