简述dubbo的SPI机制

SPI机制概述

dubbo大家都听说过吧,那么这个SPI( service provider interface )机制是啥呢?简单来说就是你有个接口,现在这个接口有3个实现类,那么在系统运行的时候,对这个接口到底选择哪个实现类呢?这就需要 spi 机制了,通常解释为:需要根据指定的配置或者是默认的配置,去找到对应的实现类加载进来,然后用这个实现类的实例对象。

结合上面那个解释来举例,默认:接口A -> 实现A1,实现A2,实现A3,重新配置一下:接口A -> 实现A2,
在系统实际运行的时候,会加载你的配置,用实现A2实例化一个对象来提供服务。

再举个dk提供功能例子,比如说你要通过 jar 包的方式给某个接口提供实现类,首先你就在自己 jar 包的 META-INF/services/目录下放一个跟接口同名的文件,然后在文件里面指定接口实现 jar 包里的某个类。

然后别人用了这个接口,用了你的jar 包,就会在运行的时候,通过你的 jar 包的那个文件,找到这个接口该用哪个实现类。

通过上面jdk例子,我们继续深入,比如说你有个工程 A 里面有个接口 A,接口A在工程A里是没有实现类的,那么系统在运行的时候,怎么给接口A选择一个实现类呢?

1、你就可以自己搞一个jar包,在 META-INF/services/ 放上一个文件,文件名就是接口名:接口A。

2、文件中实现接口A。

3、让工程A来依赖你的这个jar包。

在系统运行的时候,工程A跑起来,对接口A就会扫描自己依赖的所有的jar包,在每个jar里找找有没有 META-INF/services 文件夹,如果有,在里面找找,有没有接口A这个名字的文件,如果有,就在里面找一下你指定的接口 A 实现是你的 jar 包里的哪个类。

举了这么多例子,大家对SPI机制应该有一定了解了吧。那么这个机制一般来说用在哪儿呢?我们接着往下看。

SPI使用场景及使用

SPI机制主要是在插件扩展的场景下使用,比如说你开发的是一个给别人使用的开源框架,如果你想让别人写个插件,插到你的开源框架里面来,扩展某个功能。

首先我们先说一个 SPI 机制的经典思想体现,就是大家平时都在用的:jdbc。

java定义了一套 jdbc 的接口,但是 java 没有提供 jdbc 的实现类,但是实际上项目跑的时候,要实现 jdbc 接口,怎么办呢?一般来说,我们要根据自己使用的数据库,比如msyql,你就将 mysql-jdbc-connector.jar 引入进来;oracle,你就将 oracle-jdbc-connector.jar 引入进来。在系统跑的时候,碰到你使用 jdbc 的接口,他会在底层使用你引入的那个jar中提供的实现类。

dubbo也用了spi思想,不过没有用 jdk 的 spi 机制,是自己实现的一套spi机制,我们先说 Protocol 类, Protocol 类主要负责rpc调用,以下是代码调用实现:

Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

我来简单的解释下这个代码原理:

在系统运行的时候,使用 Protocol 接口,dubbo要判断一下应该选用这个Protocol接口的哪个实现类来实例化对象来使用。

然后他会去找一个你配置的 Protocol,找到之后他就会将你配置的 Protocol 实现类加载到 jvm 中来。

然后实例化对象时,就用你的那个 Protocol 实现类。

最后说一点,dubbo里大量使用的组件,都保留一个或多个接口实现,然后在系统运行的时候动态根据配置,去找到对应的实现类。如果你没配置,那就走默认的实现。

dubbo的SPI机制配置

上面说了使用场景,那么SPI在哪里配置呢?dubbo 在自己的 jar 里的配置,这个文件在 /META_INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol 文件中,主要配置如下:

dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
http=com.alibaba.dubbo.rpc.protocol.http.HttpProtocol
hessian=com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol

Protocol接口类代码如下:

@SPI("dubbo")  
public interface Protocol {  
      
    int getDefaultPort();  
  
    @Adaptive  
    <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;  
  
    @Adaptive  
    <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;  

    void destroy();  
  
} 

这就看到了dubbo的 spi 机制默认是怎么玩儿的了,@SPI(“dubbo”) 说的是,通过SPI机制来提供实现类,实现类是通过 dubbo 作为默认 key 去配置文件里找到的,配置文件名称与接口全限定名一样的,通过dubbo作为key可以找到默认的实现了就是.

再看这个类依赖的包文件:

com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol。

上面依赖可以看出,dubbo的默认网络通信协议就是dubbo协议,用的DubboProtocol。

如果想要动态替换掉默认的实现类,需要使用 @Adaptive 接口。在Protocol接口中,有两个方法加了@Adaptive注解,就是说那俩接口会被代理实现。

啥意思呢?

比如这个 Protocol 接口搞了俩 @Adaptive 注解标注了方法,在运行的时候会针对 Protocol 生成代理类,这个代理类的那俩方法里面会有代理代码,代理代码会在运行的时候动态根据 url 中的 protocol 来获取那个 key ,默认是dubbo,你也可以自己指定,你如果指定了别的key,那么就会获取别的实现类的实例了。

通过这个url中的参数不通,就可以控制动态使用不同的组件实现类。

如何扩展dubbo组件

最后来说说怎么来自己扩展dubbo中的组件:

首先自己写个工程,要是那种可以打成 jar 包的,在里面的 src/main/resources 目录下,搞一个META-INF/services,里面放个文件叫:com.alibaba.dubbo.rpc.Protocol,然后文件里搞一个my = com.zhss.MyProtocol。自己把 jar 弄到 nexus 私服里去。

然后自己搞一个dubbo provider工程,在这个工程里面依赖你自己搞的那个jar,然后在spring配置文件里给个配置:

<dubbo:protocol name=”my” port=”20000” />

这个时候provider启动的时候,就会加载到我们 jar 包里的 my=com.zhss.MyProtocol 这行配置里,接着会根据你的配置使用你定义好的 MyProtocol 了。

简单来说,你通过上述方式,可以替换掉大量的dubbo内部的组件。

dubbo里面提供了大量的类似上面的扩展点,就是说,你如果要扩展一个东西,只要自己写个 jar,让你的consumer 或者是 provider 工程,依赖你的那个jar,在你的 jar 里指定目录下配置好接口名称对应的文件,里面通过 key = 实现类。

然后对对应的组件,用类似 dubbo:protocol 用你的那个 key 对应的实现类来实现某个接口,你可以自己去扩展dubbo的各种功能,提供你自己的实现。

最后,我这节是完全借鉴石杉码农学院的知识

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值