乐趣区

关于前端:Dubbo的SPI自适应扩展

最近看 Dubbo 源码的时候,最开始对 Dubbo 的自适应扩大始终没怎么看明确,参考其余的博客大多也就是把官网的代码解释搬过去,然并卵。

最初依照本人的了解来模仿了一下,心愿对大家能有所帮忙。

先定义接口类 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.z 远程桌面 f.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 的自适应,在进行源码调试的时候,能够追踪到具体的实现类。

退出移动版