package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adaptive implements com.alibaba.dubbo.rpc.Protocol {
public void destroy() {
throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public int getDefaultPort() {
throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {
if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null)
throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
com.alibaba.dubbo.common.URL url = arg0.getUrl();
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.export(arg0);
}
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);
}
}
关于java SPI和dubbo SPI的简单阐述https://www1350.github.io/#post/114
拿解析一的ServiceConfig的doExportUrlsFor1Protocol为例:
这里的protocol来自
但是我们debug的时候会发现这个protocol命名是com.alibaba.dubbo.rpc.Protocol$Adaptive,可见是动态生成的。
通过ExtensionLoader的createAdaptiveExtensionClassCode方法。我们可以获取到这么一段代码。
接口如下:
我们可以看到动态生成的代码里面,通过getAdaptiveExtension获取的时候,如果没有注解@Adaptive就会把实现类写成UnsupportedOperationException,而对于@Adaptive我们看下一个动态生成的代码:
我们注意到所不同的地方在于
和
现在我们大胆猜测,@Adaptive如果没有设置参数,extName就会拿url.get+接口名;如果有设置参数,extName就会拿最后一个参数和SPI的name获取url.getParameter(最后一个参数名, SPI名),得到的结果在用url.getParameter(倒数第二个参数名,上一个结果),一直这样直到取完参数。另外还通过官方文档了解到,接口方法不注解@Adaptive,在实现类注解@Adaptive将会自动激活这个拓展。
另外一点我们注意到不管参数顺序如何,都能拿到url,这里可能进行了类型判断。接下来我们就验证下想象。
获取SPI,并获取
我们进入到了SPI机制的核心,通过loadFile可以加载到所有配置的类:
下面是$Adaptive类生成的代码:
现在我们还有个疑问?如果只分析这些代码,会认为最开始的解析一例子,暴露的是RegistryProtocol,然而外面又包裹了两层:ProtocolListenerWrapper和ProtocolFilterWrapper,这是如何实现的呢?
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
拿到的是ProtocolListenerWrapper,下面我们分析下getExtension,他最终通过createExtension创建对象实例