为什么说SPI打破双亲委派机制?

5 篇文章 0 订阅

简单介绍ClassLoader的双亲委派机制:

java类通过Classloader加载,Classloader之间有继承关系,AppClassLoader继承ExtClassloader继承BootstrapClassloader。在类加载时,子加载器会调用父加载器来加载类,如果父加载器不能加载类,才会交给子加载器来加载;如果子加载器也加载失败,那么就报异常。

可以看出双亲委派机制是一种至下而上的加载方式,那么SPI是如何打破这种关系?
以JDBC加载驱动为例:
在JDBC4.0之后支持SPI方式加载java.sql.Driver的实现类。SPI实现方式为,通过ServiceLoader.load(Driver.class)方法,去各自实现Driver接口的lib的META-INF/services/java.sql.Driver文件里找到实现类的名字,通过Thread.currentThread().getContextClassLoader()类加载器加载实现类并返回实例。

驱动加载的过程大致如上,那么是在什么地方打破了双亲委派模型呢?

先看下如果不用Thread.currentThread().getContextClassLoader()加载器加载,整个流程会怎么样。

  1. 从META-INF/services/java.sql.Driver文件得到实现类名字DriverA
  2. Class.forName("xx.xx.DriverA")来加载实现类
  3. Class.forName()方法默认使用当前类的ClassLoader,JDBC是在DriverManager类里调用Driver的,当前类也就是DriverManager,它的加载器是BootstrapClassLoader。
  4. 用BootstrapClassLoader去加载非rt.jar包里的类xx.xx.DriverA,就会找不到
  5. 要加载xx.xx.DriverA需要用到AppClassLoader或其他自定义ClassLoader
  6. 最终矛盾出现在,要在BootstrapClassLoader加载的类里,调用AppClassLoader去加载实现类

这样就出现了一个问题:如何在父加载器加载的类中,去调用子加载器去加载类?

  1. jdk提供了两种方式,Thread.currentThread().getContextClassLoader()和ClassLoader.getSystemClassLoader()一般都指向AppClassLoader,他们能加载classpath中的类
  2. SPI则用Thread.currentThread().getContextClassLoader()来加载实现类,实现在核心包里的基础类调用用户代码

打破双亲委派原则的方式:

     1.自定义类加载器,重写ClassLoader类中的findClass()

     2.jdk提供了两种方式,Thread.currentThread().getContextClassLoader()和ClassLoader.getSystemClassLoader()一般都指向AppClassLoader,他们能加载classpath中的类

 

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值