JAVA SPI 和双亲委派的理解

SPI:简单理解就是一个规则,规定在META-INF中的services目录下声明一个以接口的全限定名为文件名的文件,里面写上实现类的全限定名。java的数据库驱动就是个很好的例子,如下:
在这里插入图片描述
这样jdk厂商就不用关心具体驱动实现了只是把这个接口给了出来,其他数据库厂商就自个实现去吧。或许某一天自己做出个数据库来要兼容到java同样的也就按这种方式进行驱动的编写最后打成jar包别人就可以引用了。

双亲委派:在jvm加载class时需要使用类加载器进行加载,而在java中一共有3种:
Bootstrap Classloader 启动类加载器:负责加载/lib 下的核心类库,此加载器本身内嵌于JVM,在 Java 中找不到具体的引用,其是C++实现的;
Extension Classloader 扩展类加载器:负责加载/lib/ext 下的扩展类库;
Application Classloader 系统应用类加载器:负责-classpath 指定路径类库加载。
下层加载器在加载之前会移交给上层,上层没有才一级一级移交给下层加载,这样做的目的是保证了安全性和唯一性,比如我写个全限定名和jdk一样的String类,是否就破坏了系统代码?但由于双亲委派的存在加载String时会移交给最上层,最后再jdk包中就会找到正常jdk的String类避免程序员做手脚,另一方面在jvm中判断两个类是否一样除了全限定名还要看加载器,只有两个都一样时才能确认相等。
ContextClassLoader:这时一种特殊的类加载器,主要用于打破双亲委派,其实按我理解应该不是打破,而是绕开。
在SPI中核心类就是ServiceLoader ,通过它就可以加载接口的实现类这里面就涉及到了打破双亲委派,ServiceLoader有一个load方法使用到了ContextClassLoader:

    public static <S> ServiceLoader<S> load(Class<S> service) {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        // 使用当前线程的ClassLoader进行加载待加载的实现类
        return ServiceLoader.load(service, cl);
    }
 

这里的ServiceLoader是属于Boot加载器 所加载的类,而SPI实现类都是三方jar包,如果没有这里的打破双亲委派那么这里会报classnotfound的错,因在Boot所加载的包中是无法拿到app加载器所加载的类,打破双亲委派主要就是看contextclassloader,它会拿到实现类的加载器。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值