分享

Dubbo的SPI自适应扩展

 小熊丫丫01 2021-02-01

最近看Dubbo源码的时候,最开始对Dubbo的自适应扩展一直没怎么看明白,参考其他的博客大多也就是把官方的代码解释搬过来,然并卵。

SPI不明白可以参考官方文档

最后按照自己的理解来模拟了一下,希望对大家能有所帮助。

先定义接口类 SpiTest,有一个mySpi方法:

@SPI //标记为扩展接口public interface SpiTest{

    void mySpi(URL url, String name);

}

有两个实现类S1和S2:

public class S1 implements SpiTest{

    @Override

    public void mySpi(URL url, String name) {

        System.out.println("This is S1 : "+name);

    }

}

public class S2 implements SpiTest{

    @Override

    public void mySpi(URL url,String name) {

        System.out.println("This is S2 : "+name);

    }

}

META-INF/dubbo下创建文件com.xx.dubbospi.SpiTest

S1=com.zf.xx.dubbospi.S1

S2=com.zf.xx.dubbospi.S2

在正常使用的时候可以通过 ExtensionLoader.getExtensionLoader(SpiTest.class).getExtension("S1")来获取SpiTest的某一个实现,但是如果在方法调用时不确定具体实现类怎么办?可以定义一个包装类SpiWrapper ,包装类不具体实现方法,只是根据参数获取对应的扩展对象来执行,根据传入的参数来获取到底时S1还是S2:

public class SpiWrapper implements SpiTest{

    @Override

    public void mySpi(URL url,String name) {

       SpiTest spiTest = ExtensionLoader.getExtensionLoader(SpiTest.class).getExtension(url.getParameter("spi.test"));//通过参数指定需要加载的对象

        spiTest.mySpi(url,name);

    }

    public static void main(String[] args) {

        URL url = new URL("dubbo","123",999);//这里的URL是 org.apache.dubbo.common.URL

        url = url.addParameter("spi.test","S2");

        SpiWrapper spiWrapper = new SpiWrapper();

        spiWrapper.mySpi(url,"tudou");

    }

}

SpiWrapper 中会根据url上的参数spi.test的值类决定到底取SpiTest的哪一个实现类,这样就实现的SPI的一个动态扩展。而在Dubbo中具体的使用需要先对SpiTest进行改造:

@SPIpublic interface SpiTest{

    @Adaptive

    void mySpi(URL url, String name);

}

在方法上增加注解 @Adaptive,Adaptive就是告诉Dubbo应该使用哪一个实现类来调用mySpi方法。实现逻辑就是通过约定在URL(key-value)中提取 key值,通过key值来决定实现类。比如我们使用 protocol为Dubbo,那么通过yml文件指定dubbo.protocol.name为dubbo,在URL上的格式就是 protocol=dubbo,后续执行服务流量交易导出 export的时候就会加载DubboProtocol来实现。

@SPI("dubbo") //默认dubbo

public interface Protocol {

@Adaptive

    <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;

}

配置文件

filter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper

listener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper

mock=org.apache.dubbo.rpc.support.MockProtocol

dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol

injvm=org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol

http=org.apache.dubbo.rpc.protocol.http.HttpProtocol

rmi=org.apache.dubbo.rpc.protocol.rmi.RmiProtocol

hessian=org.apache.dubbo.rpc.protocol.hessian.HessianProtocol

org.apache.dubbo.rpc.protocol.webservice.WebServiceProtocol

thrift=org.apache.dubbo.rpc.protocol.thrift.ThriftProtocol

native-thrift=org.apache.dubbo.rpc.protocol.nativethrift.ThriftProtocol

memcached=org.apache.dubbo.rpc.protocol.memcached.MemcachedProtocol

redis=org.apache.dubbo.rpc.protocol.redis.RedisProtocol

rest=org.apache.dubbo.rpc.protocol.rest.RestProtocol

xmlrpc=org.apache.dubbo.xml.rpc.protocol.xmlrpc.XmlRpcProtocol

grpc=org.apache.dubbo.rpc.protocol.grpc.GrpcProtocol

registry=org.apache.dubbo.registry.integration.RegistryProtocol

service-discovery-registry=org.apache.dubbo.registry.client.ServiceDiscoveryRegistryProtocol

qos=org.apache.dubbo.qos.protocol.QosProtocolWrapper

再来看我们的例子:

public class SpiWrapper implements SpiTest{

    @Override

    public void mySpi(URL url,String name) {

        //主要通过在Url上找到 spi.test 参数的值 , ExtensionLoader.getExtensionLoader(SpiTest.class).getExtension("S1")

        SpiTest spiTest = ExtensionLoader.getExtensionLoader(SpiTest.class).getAdaptiveExtension();//通过url参数获取自适应对象

        //SpiTest spiTest = ExtensionLoader.getExtensionLoader(SpiTest.class).getExtension(url.getParameter("spi.test"));

        spiTest.mySpi(url,name);

    }

    public static void main(String[] args) {

        URL url = new URL("dubbo","123",999);

        url = url.addParameter("spi.test","S1");//指定url参数

        SpiWrapper spiWrapper = new SpiWrapper();

        spiWrapper.mySpi(url,"tudou");

    }

}

通过指定URL的参数,就可以自动加载对应的扩展实现类。具体的ExtensionLoader源码分析,官网写的很详细,有兴趣可以看一下。

Dubbo源码中大量使用了SPI的动态扩展,如果不弄清楚,可能对学习源码会是一个比较大的阻碍。希望这篇文章能帮助大家进一步的理解SPI的自适应,在进行源码调试的时候,可以追踪到具体的实现类。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多