前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >dubbo SPI 主要配置技术解读

dubbo SPI 主要配置技术解读

原创
作者头像
技术蓝海
修改2020-10-26 12:06:34
8321
修改2020-10-26 12:06:34
举报
文章被收录于专栏:wannshan(javaer,RPC)wannshan(javaer,RPC)

所谓SPI就是接口由框架定义,具体实现可以有不同供应商提供不同的实现。

dubbo在JDK基础上对SPI做了改进和扩展。

dubbo 的SPI 不但实现了实现类的动态加载,还实现了类似spring 的IOC,AOP的功能

本文就上述功能讲下具体使用方法

基本SPI 配置

dubbo 源码包的有些模块的 META-INF/dubbo/目录下 有以接口名命名的文件,里面有是 name=类全面形式的内容

比如

代码语言:javascript
复制
META-INF/dubbo/org.apache.dubbo.rpc.Protocol 文件的内容有
dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol

DubboProtocol的实现类是dubbo默认的调用协议实现

这样就可以在我们使用dubbo的配置文件中,通过 name 指定我们用的Protocol具体哪个实现

代码语言:javascript
复制
<dubbo:protocol name="dubbo"/>

同样你可以添加自己的实现类,比如x.y.z.XXXProtocol 让后在META-INF/dubbo/org.apache.dubbo.rpc.Protocol 文件中添加 新的一行 xxx=x.y.z.XXXProtocol 然后就可以在配置中使用了,这就是最基本的SPI功能。

IOC功能

dubbo不只是还实现了依赖注入的功能,比如DubboProtocol 先类种有个属性filter

代码语言:javascript
复制
public class DubboProtocol extends AbstractProtocol {
    public Filter filter;
    public void setFilter(Filter filter) {
        this.filter = filter;
    }
...
}

Filter 本身也一个接口,可以是@SPI接口,也可以是spring的一个bean

dubbo也可以自动从dubbo 扩展或者spring容器中找到实现类型自动注入

有个问题,如果dubbo org.apache.dubbo.rpc.Filter的文件中有多个实现配置,比如

代码语言:javascript
复制
mockfilter=org.apache.dubbo.config.mock.MockFilte
orc=org.apache.dubbo.config.orc.OrcFilte
mov=org.apache.dubbo.config.mov.MovFilter

应该用哪一个类呢?这就要用到Adaptive注解,比如

代码语言:javascript
复制
@Adaptive
public class MockFilter implements Filter {}

这个就表示用 MockFilter类作为实现类

关于@Adaptive注解,它还能写在接口方法上,如果不在类上指定dubbo 会为这个接口自动生成一个 接口名$Adpative 命名的实现类。比如 dubbo Protocol接口 refer方法

代码语言:javascript
复制
@SPI("dubbo")
public interface Protocol {
    @Adaptive //没在类中指定,写在了方法上
    <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
.....
}

dubbo 动态生成的Adapatvie类和refer方法实现如下:

代码语言:javascript
复制
public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol {
   .....
    public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException {
        if (arg1 == null) throw new IllegalArgumentException("url == null");
        com.alibaba.dubbo.common.URL url = arg1;
        String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        if (extName == null)
            throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
        com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.refer(arg0, arg1);
    }
......
}

可以看到,它实现的功能就是通过调用时url中的参数指定具体哪个实现类。

AOP

AOP就动态方法包装,完成切面编程,dubbo是通过 wrapper类实现的。

还是文件org.apache.dubbo.rpc.Protocol 文件,里面有这些配置

代码语言:javascript
复制
filter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrappe
listener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrappe
mock=org.apache.dubbo.rpc.support.MockProtocol

其中 ProtocolFilterWrapper就是Wrapper类,并不是因为类名有Wrapper,而是由于实现中有Protocol 接口类型的构造函数

代码语言:javascript
复制
@Activate(order = 100)
public class ProtocolFilterWrapper implements Protocol {
    private final Protocol protocol;
    public ProtocolFilterWrapper(Protocol protocol) {
        if (protocol == null) {
            throw new IllegalArgumentException("protocol == null");
        }
        this.protocol = protocol;
    }
...
   //对refer实现了包装
    @Override
    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
        if (UrlUtils.isRegistry(url)) {
            return protocol.refer(type, url);
        }
        return buildInvokerChain(protocol.refer(type, url), REFERENCE_FILTER_KEY, CommonConstants.CONSUMER);
    }
}
//另外一个Wrappe
@Activate(order = 200)
public class ProtocolListenerWrapper implements Protocol {
    private final Protocol protocol;
    public ProtocolListenerWrapper(Protocol protocol) {
        if (protocol == null) {
            throw new IllegalArgumentException("protocol == null");
        }
        this.protocol = protocol;
    }
...
}

想必你注意到了@Activate(order = 200)注解,它指定多个wrapper 的排序,通过@Activate的order属性排序。

Activate

比如常用的Filter, InvokerListener, ExportListener, TelnetHandler, StatusChecker 等实现集合,我们可以通过 Activate注解完成多个实现类的一次加载和激活,还能配置条件激活,比如

代码语言:javascript
复制
@Activate // 任何条件下激活
public class XxxFilter implements Filter {
    // ...
}
@Activate(group = "provider", value = "cache") //这个就是在group是“provider”  value 等于cache 下激活
public class CacheFilter  implements Filter {
    // ...
}

这个功能的实现可看 ExtensionLoader类的getActivateExtension方法:

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基本SPI 配置
  • IOC功能
  • AOP
  • Activate
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档