手写dubbo框架9-SPI实现

    博客中代码地址: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重点,代码中都有标注有注释,应该很清楚。这里看一下怎么使用。

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初始化对象

测试
@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。例如

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路由要你需要的负载均衡算法。如下:

farpc.cluster.loadbalance=random
SPI扩展注册中心

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

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

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

farpc.registry.protocol=zookeeper
farpc.registry.address=127.0.0.1:6379
farpc.cluster.loadbalance=random

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

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

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值