手写dubbo框架6-SPI(预热篇)

    博客中代码地址:https://github.com/farliu/farpc.git

    本章不讲述其他SPI博文所说的细节,SPI博文实在太多了。但你可以在本章了解到SPI作用以及其他博文中没有解释详细的地方。继续看上面这张图,SPI其实不属于图中的任何一个环节。但是它对dubbo尤为重要,也是非常值得一说的内容。

dubbo选择SPI背景及作用

    在众多dubbo源码解析的博文,都会将SPI做重点来解说,可见它对dubbo多么重要。那么我们先来了解一下SPI的背景。我在官方的quick start中找到这样一句话。

    大概的意思就是告诉我们,dubbo可以只依赖JDK,不依赖于任何三方库就可以运行。这其实也是dubbo设计者的一个夙求。

    聊dubbo的SPI之前,我们先聊聊spring,spring最值得吹捧的功能就是IOC。而IOC自然也是整个开发历程的必然产物,因为当众多框架(MVC、ORM)诞生后,肯定是需要有这样一个东西来将多个框架粘合在一次的。而IOC就是这样一个粘合剂,它作为粘合剂实现的方案就是将大家的bean管理在一起,以此达到相互调用。

    那么dubbo设计者不想让dubbo依赖任何第三方库就能运行,难道它就没有IOC这样的需求吗?自然是有的。那么dubbo选择的解决方案就是使用SPI,基于jdk原生的SPI帮助dubbo创建类的对象。那么我们暂且可以将SPI简单的理解为它帮助dubbo初始化对象。

    SPI的作用,我们暂且这么理解了。那么dubbo用它来做了什么呢?我们模拟一下场景,dubbo作为一款优秀的框架,肯定需要适配各样的场景,例如:

  1. 注册中心,用户可以选择zookeeper、redis...

  2. rpc协议,用户可以选择netty、http...

  3. 负载均衡,用户需要根据自己硬件配置选择负载均衡策略

    这就到了SPI的登场的时候了。dubbo对于需要提供扩展的接口,例如我们上一章的ILoadbalance,使用SPI根据用户的配置初始化对应的实现类。而程序在运行时只需要关注调用对应的接口就行了。

补充众多SPI博文中没有讲述的

    说SPI,众多博客中都会提到API,简单的说,api是给使用者使用的,spi是给拓展者使用的。这句话没错,但是为什么?为什么要设计SPI?还有所谓的拓展者是谁?

    从开发能力上说,框架作者能做到的功能,我们普通开发者也一定能做到,只是代码实现优雅,性能略有缺陷。作为一个使用者,肯定会有根据公司产品对某一方面定制化的需求。而dubbo作为一款通用框架,总会有一些什么地方满足不了你定制化的需求,比如说你要根据公司自己的传输协议,传输数据来调用dubbo,这个需求其实很合理。在rpc初级阶段,一些大厂都会自己尝试,就会定义各种自己公司特色的东西,那么dubbo这时肯定不支持。那么这时怎么处理,难道向dubbo开发方pull request?而分支,质量,合并,冲突都会很难管理。

    以上是开发的一个痛点,那么dubbo是怎么解决的呢。他在很多地方使用SPI提供了扩展点,当你有定制化需求时,你可以根据SPI的规范,很容易的将自己定制好的某一个功能插在dubbo运行过程中。比如你要定义一个自己的协议。那么你只需要完成以下几步

  1. 实现org.apache.dubbo.rpc.Protocol。实现定制化需求。

  2. 在resource/META-INF/dubbo,新建名字为org.apache.dubbo.rpc.Protocol的文件。将自己实现的协议维护在里面。

org.apache.dubbo.rpc.Protocol:
xxx=com.xxx.XxxProtocol
  1. 在dubbo的配置中写上你的协议名字:xxx

<!-- 声明协议,如果没有配置id,将以name为id -->
<dubbo:protocol id="xxx1" name="xxx" />

    那么这个时候可以回答那两个问题。为什么要设计SPI?设计SPI的目的就是为方便使用者对已有功能进行扩展,满足使用者定制化的需求。扩展者是谁?扩展者指的就是我们,当我们需要适配自己定制需求时,可以使用SPI扩展点进行扩展。

    dubbo扩展点可在官网查看:http://dubbo.apache.org/zh-cn/docs/dev/impls/protocol.html

SPI简单应用

    本节使用jdk的SPI,尽量说明SPI的作用。

public interface IWelcome {
    void say();
}
public class LadyWelcome implements IWelcome {
    @Override
    public void say() {
        System.out.println("lady: welcome to SPI.");
    }
}
public class GentlemenWelcome implements IWelcome {
    @Override
    public void say() {
        System.out.println("gentlemen: welcome to SPI.");
    }
}

    新建文件META-INF/services/com.ofcoder.xxx.IWelcome

com.ofcoder.xxx.GentlemenWelcome
com.ofcoder.xxx.LadyWelcome

    测试代码,与结果。

public class Main {
    public static void main(String[] args) {
        ServiceLoader<IWelcome> loads = ServiceLoader.load(IWelcome.class);
        for (IWelcome load : loads) {
            load.say();
        }
    }
}
------------------------
gentlemen: welcome to SPI.
lady: welcome to SPI.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值