适配器模式通过定义一个新的接口(对要实现的功能加以抽象),和一个实现该接口的Adapter(适配器)类来透明地调用外部组件。这样替换外部组件时,最多只要修改几个Adapter类就可以了,其他源代码都不会受到影响。
从上面的适配器模式定义可以看出,所谓的适配器模式是针对一个接口,通过一个实现类Adapter来动态的替换具体需要的实现类。
在Dubbo中由于几乎所有的功能点都是由SPI来实现的,因此不可避免的产生的大量的接口和其对应的实现类,因此Dubbo采用适配器模式,来选择具体的业务操作室需要用的的真正的实现类。
用Protocol接口来说
在serviceConfig.export()的时候,Dubbo会根据动态编译技术来为Protocol生成一个Protcol$Adaptive的实例对象,该对象是实现了Protocol,其中的export()方法,通过获取Dubbo的URL的protoclo的值,来确定需要用到的具体的实现,
serviceConfig.export()->protocol.export()->protocol$Adaptive.export()->protocolImpl.export()->打开netty监听,向注册中心发布服务的操作。
因此在调用Protocol.export()的时候就变成通过适配器来调用真正的实现 的export()方法。
生成的Protocol代码
package org.apache.dubbo.rpc;
import org.apache.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol {
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!");
}
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 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);
}
}
(如果想看到别的SPI的Adaptive可以通过断点查看)
image.png
Dubbo中,会给每一个SPI扩展接口都进行此操作
网友评论