前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Dubbo 是如何实现 SPI 机制?

Dubbo 是如何实现 SPI 机制?

作者头像
FoamValue
发布2020-10-23 10:16:07
7400
发布2020-10-23 10:16:07
举报
文章被收录于专栏:FoamValueFoamValue

SPI 全称是 Service Provider Interface,是一种服务发现机制。

如果对 Java SPI 实现不了解的同学,可以先看下往期的介绍:「周末福报」你了解 SPI 吗?


SPI 在 Dubbo 中是一个非常重要的模块。大量的 SPI 文件,如下图。

JDK SPI 的原理是在 resources/META-INF/service 目录下添加一个全路径接口名的文件,例如:org.apache.dubbo.common.extension.LoadingStrategy

,每一行都是接口实现类。

Dubbo SPI 是在 JDK SPI 的基础上重新实现了一套更强功能的 SPI 机制。它定义了两个新的目录 resources/META-INF/dubbo、resources/META-INF/dubbo.internal 与 JDK SPI 进行区分,例如:org.apache.dubbo.common.compiler.Compiler,每一行都是 Key=Value 的键值对格式。


SPI 源码

Dubbo SPI 的源码,存在放 dubbo-common 的 extension 扩展包中。

源码可以分为 @interface、interface、class,也就是注解、抽象接口、实现类。

@interface

Dubbo 的自定义注解 SPI、DisableInject、Adaptive、Activate。其中 SPI 是核心注解,它代表了接口启用 Dubbo SPI、也代表了接口使用哪个扩展实现类,例如:Protocol,将使用 DubboProtocol 这个实现类。

DisableInject 是禁止注入注解。Adaptive 是自适应扩展注解,拥有一个字符串数组的 value 属性。Activate 是给定条件自动激活某些扩展的注解,拥有字符串数组的 group、value 属性。

interface

ExtensionFactory @SPI 修饰的工厂接口,提供一个返回值是泛型的 getExtension 接口。

LoadingStrategy 加载策略接口,使用 JDK SPI 机制提供三个实现类。

class

ServicesLoadingStrategy、DubboLoadingStrategy、DubboInternalLoadingStrategy 分别对应 META-INF/services/、META-INF/dubbo/、META-INF/dubbo/internal/ 目录。

ActivateComparator 实现了 Comparator 接口,实现了对 Activate 注解的 order 属性排序功能。

AdaptiveExtensionFactory 工厂类,初始化时会自动进行加载。

SpiExtensionFactory 工厂类,获取返回类型前需要校验 type 是接口,以及是否拥有 SPI 注解修饰。

AdaptiveClassCodeGenerator 是 Adaptive Class 的代码生成器。

简单的解释就是,通过约定的规则进行的 Class 文件内容的字符串拼接。网上找到了一段拼接后的实例,可以参考一下:

package org.apache.dubbo.rpc;
import org.apache.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol {
    public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, org.apache.dubbo.common.URL arg1) throws org.apache.dubbo.rpc.RpcException {
        if (arg1 == null) throw new IllegalArgumentException("url == null");
        org.apache.dubbo.common.URL url = arg1;
        String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
        if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
        org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.refer(arg0, arg1);
    }
    public org.apache.dubbo.rpc.Exporter export(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException {
        if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
        if (arg0.getUrl() == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
        org.apache.dubbo.common.URL url = arg0.getUrl();
        String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
        if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
        org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.export(arg0);
    }
    public void destroy()  {
        throw new UnsupportedOperationException("The method public abstract void org.apache.dubbo.rpc.Protocol.destroy() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }
    public int getDefaultPort()  {
        throw new UnsupportedOperationException("The method public abstract int org.apache.dubbo.rpc.Protocol.getDefaultPort() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }
}
ExtensionLoader 是加载 Dubbo 扩展的类。

大量的 ConcurrentMap、volatile 运用在扩展实例上,例如:cachedInstances 属性。


总结

Dubbo SPI 机制是通过自定义的注解、类生成器,以及加载扩展类的方式来实现的。

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

本文分享自 FoamValue 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档