SPI : ServiceLoader如何打破双亲委派

本文探讨了ServiceLoader如何利用SPI机制打破Java类加载器的双亲委派模型,通过特定方式实例化不同类加载器下的类。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

接上篇继续:SPI : Service Provider Interface

ServiceLoader打破双亲委派


我们知道jdk的核心API(e.g rt.jar)是BootstrapClassLoader加载的,三方提供的jar包是AppClassLoader加载的,那么ServiceLoader是rt.jar中的类,那么对应的加载器就是BootstrapClassLoader

那么问题来了。

如果一个类由类加载器加载,那么这个类依赖的类也是由相同的类加载器加载的。

很显然,ServiceLoader这里打破了双亲委派机制。


如何做到的呢?
写一段代码做个测试。

 public static void main(String[] args) {
     ServiceLoader<Driver> loader = ServiceLoader.load(Driver.class);

     Iterator<Driver> iterator = loader.iterator();

     while (iterator.hasNext()){
          Driver driver = iterator.next();
          System.out.println("driver:"+driver.getClass());
          System.out.println("classLoader:"+driver.getClass().getClassLoader());
      }

      System.out.println("current thread classLoader:"+Thread.currentThread().getContextClassLoader());

      System.out.println("ServiceLoader loader:"+ServiceLoader.class.getClassLoader());
   }

我们在这个项目中引入了MySQL的jar包。执行结果如下:

driver:class com.mysql.cj.jdbc.Driver
classLoader:sun.misc.Launcher$AppClassLoader@18b4aac2
current thread classLoader:sun.misc.Launcher$AppClassLoader@18b4aac2
ServiceLoader loader:null

从结果上我们可以看到,已经找到了MySQL的驱动。这里如果再引入Oracl的驱动的话,那么也会打印出来,就不做测试了。这其实就是JDK标准的SPI的一个特性:加载SPI接口的所有实现类。

另外,从执行结果上我们可以看到ServiceLoader的加载器是BootStrapClassLoader,因为最后一行输出了null,并且从该类在rt.jar里边也可以说明这一点了。两种不同的classLoader说明传统的双亲委派确实被打破。

ServiceLoader.load(Driver.class)入手找打破双亲委派的方式。
在这里插入图片描述
可以看到,第一行获取了当前线程上下文加载器,也就是AppClassLoader
第二行做的其实就是通过构造方法将获得的cl赋值给ServiceLoader的成员变量loader

// The class loader used to locate, load, and instantiate providers
private final ClassLoader loader;

那么这个成员变量loader是什么时候用的呢?

我们调用next()方法的时候,这时候会触发一个类加载,由下边代码可以看到先是在Class.forName获取class的时候使用上边的成员变量loader,然后clazz.newInstance生成对象。
在这里插入图片描述

由此,JDK通过ServiceLoader实现的SPI打破了双亲委派

尝试几句话说清楚:
加载器是BootStrapClassLoaderServiceLoader在实例化本身时,将当前线程上上下文加载器赋值给本身的一个成员变量。后续需要实例化SPI接口时,通过这个成员变量去做实例化动作,从而实现了打破双亲委派。
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高级摸鱼工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值