前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >手写dubbo框架9-SPI实现

手写dubbo框架9-SPI实现

作者头像
并发笔记
发布2020-10-23 09:57:38
5970
发布2020-10-23 09:57:38
举报
文章被收录于专栏:并发笔记

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

项目结构介绍

本节涉及博客中代码的三个module,farpc-registry(服务治理)、farpc-cluster(集群管理),farpc-common

本章重点就是farpc-common。而SPI具体实现方案就是ExtensionLoader。本章大部分代码都从dubbo源码中提取。

我们在贴代码之前还是讲讲涉及到的类前后推理的逻辑。ExtensionLoader为SPI重要实现类,本章实现的简单的SPI其实有这个类就够了。但是在dubbo中还提供了两个辅助类,我觉得有必要就也加进来一起聊聊,一个是FarSPI注解,一个是Holder。

SPI实现

本章代码量有点大,下面贴代码会导致篇幅过长,我们针对涉及的几个都分别解析一下,具体代码大家可以上github自己clone。我们对照项目结构一个个分析。

FarSPI

FarSPI注解用来标注接口的默认配置对象。

Holder

Holder用来包装对象实例,上两章中有提到dubbo中很多地方用到了double-check-lock,它虽然能保证并发,但是出现重排序时,调用者拿到的对象可能是一个未初始化的地址。所以使用Holder对其包装,利用volatile保证可见性

ExtensionLoader

ExtensionLoader做SPI重点,代码中都有标注有注释,应该很清楚。这里看一下怎么使用。

代码语言:javascript
复制
ILoadbalance extension = ExtensionLoader.getExtensionLoader(ILoadbalance.class).getExtension(loadbalance)
Property、PropertyUtil

这两个类是为了读取用户的配置写的,dubbo会解析xml,我这里由用户在application.properties中指定。

使用

SPI其实就靠上面几个类就能运行了,现在说说怎么使用,我在ExtensionLoader中读取META-INF/farpc/下面的文件,我们需要将SPI的配置放在该文件夹下,文件名字为接口的全路径。

例如:让SPI创建ILoadbalance的对象。在之前我们实现了两个ILoadbalance的方案RoundLoadBalanceImpl、RandomLoadbalanceImpl。

以及在之前我们实现了两种注册中心,也可以交由SPI初始化对象

测试
代码语言:javascript
复制
@Test
public void spiTest(){
    ILoadbalance round = ExtensionLoader.getExtensionLoader(ILoadbalance.class)
            .getExtension("round");
    ILoadbalance random = ExtensionLoader.getExtensionLoader(ILoadbalance.class)
            .getExtension("random");
    System.out.println(round.getClass().getName());
    System.out.println(random.getClass().getName());
}

------------------------------------
com.ofcoder.farpc.cluster.loadbalance.RoundLoadBalanceImpl
com.ofcoder.farpc.cluster.loadbalance.RandomLoadbalanceImpl
在项目中优雅使用
SPI扩展负载均衡

在项目启动时,Property类会加载用户的配置。我在代码中是由一个LoadbalanceFactory去调用SPI的。就是类似dubbo SPI的自适应机制,在dubbo中自适应机制是由dubbo生成代理类去完成对实现类调用的路由,我这里是直接写死由Factory去管理。

在之前讲述服务发现的代码时,我也留下了伏笔AbstractRegistrar,那么这一节,我们可以在AbstractRegistrar中调用LoadbalanceFactory。例如

代码语言:javascript
复制
public abstract class AbstractRegistrar implements IRegistrar {
    public String discover(String service) {
        List<String> providers = lookup(service);
        ILoadbalance loadbalance = LoadbalanceFactory.getLoadbalance();
        String select = loadbalance.select(providers);
        return select;
    }

    public abstract List<String> lookup(String service);
}

然后在配置文件application.properties中,指定loadbalance方式,就可以由Factory路由要你需要的负载均衡算法。如下:

代码语言:javascript
复制
farpc.cluster.loadbalance=random
SPI扩展注册中心

按照上面的设计模式,我们其实还可以管理注册中心、调用协议、序列化方式,等等等等....例如,我们在使用SPI加载注册中心。

注册中心的地址和端口,一般也是不会变的,我也把它放在配置文件中,在AbstractRegistrar的构造中将注册中心的地址传给ZookeeperRegistrarImpl和RedisRegistrarImpl,交由他们各自去实现,并AbstractRegistrar来调用。

代码语言:javascript
复制
public abstract class AbstractRegistrar implements IRegistrar {
    protected static final String FOLDER = "/faregistrys";
    protected static final String SEPARATOR = "/";

    public AbstractRegistrar() {
        String address = Property.Registry.address;
        init(address);
    }

    public String discover(String service) {
        List<String> providers = lookup(service);
        ILoadbalance loadbalance = LoadbalanceFactory.getLoadbalance();
        String select = loadbalance.select(providers);
        return select;
    }

    protected abstract void init(String address);

    protected abstract List<String> lookup(String service);
}

application.properties

代码语言:javascript
复制
farpc.registry.protocol=zookeeper
farpc.registry.address=127.0.0.1:6379
farpc.cluster.loadbalance=random

完成上面的优化,我们调用时就可以极其简洁,并且新拓展其他注册中心也只要实现AbstractRegistrar的抽象接口就行,对已有的代码没有任何侵入。

代码语言:javascript
复制
@Test
public void spiTest() throws IOException {
    IRegistrar registrar = RegistrarFactory.getRegistrar();
    registrar.register("127.0.0.1:62880", IWelcome.class.getName());
    System.in.read();
}

这一节没有对各个类的代码讲述,可能有点跳跃。不过代码很简单,稍微瞥一眼就行。这个系列,我们实现的RPC调用,意义在于了解整个调用过程。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-10-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 并发笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 项目结构介绍
  • SPI实现
    • FarSPI
      • Holder
        • ExtensionLoader
          • Property、PropertyUtil
            • 使用
              • 测试
              • 在项目中优雅使用
                • SPI扩展负载均衡
                  • SPI扩展注册中心
                  相关产品与服务
                  负载均衡
                  负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档