dubbo源码需要先了解dubbo的SPI机制,官网说明如下
http://dubbo.apache.org/zh-cn/docs/source_code_guide/dubbo-spi.html
入口 org.apache.dubbo.config.spring.ReferenceBean 的 afterPropertiesSet(),跳过前面一些配置检查直接看 getObject()
进入getObject()
接着进入就到了 ReferenceConfig 中
进入init() 直接看 ref = createProxy(map);
看到 invoker = REF_PROTOCOL.refer(interfaceClass, urls.get(0)); 因为只配置了一个注册中心,所以走 if 逻辑
REF_PROTOCOL 是一个扩展点,注释也写的很清楚,此时的 url 如下
registry://192.168.50.135:2181/org.apache.dubbo.registry.RegistryService?application=springboot-dubbo-client&dubbo=2.0.2&pid=2468&qos.enable=false&refer=application%3Dspringboot-dubbo-client%26dubbo%3D2.0.2%26interface%3Dcom.david.dubbo.SayHelloService%26lazy%3Dfalse%26methods%3DsayHello%2CsayHi%2CsayBye%26pid%3D2468%26qos.enable%3Dfalse%26register.ip%3D192.168.50.1%26release%3D2.7.3%26revision%3D1.0-SNAPSHOT%26side%3Dconsumer%26sticky%3Dfalse%26timestamp%3D1588126009153®istry=zookeeper&release=2.7.3×tamp=1588126009283
根据协议生成的是 RegistryProtocol
REF_PROTOCOL是一个自适应扩展点,根据之前的经验会获得一个RegisterProtocol,查看生成类
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);
}
}
进入 RegisterProtocol 的 refer
这里下面这段代码把url中的协议替换成了zookeeper
url = URLBuilder.from(url).setProtocol(url.getParameter("registry", "dubbo")).removeParameter("registry").build();
此时 registryFactory 是一个injection注入类
debug查看生成代码
public class RegistryFactory$Adaptive implements org.apache.dubbo.registry.RegistryFactory {
public org.apache.dubbo.registry.Registry getRegistry(org.apache.dubbo.common.URL arg0) {
if (arg0 == null) throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg0;
String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
if (extName == null)
throw new IllegalStateException("Failed to get extension (org.apache.dubbo.registry.RegistryFactory) name from url (" + url.toString() + ") use keys([protocol])");
org.apache.dubbo.registry.RegistryFactory extension = (org.apache.dubbo.registry.RegistryFactory) ExtensionLoader.getExtensionLoader(org.apache.dubbo.registry.RegistryFactory.class).getExtension(extName);
return extension.getRegistry(arg0);
}
}
因为 protocol 是 zookeeper 所以会调用 ZookeeperRegistryFactory 的 getRegister()
ZookeeperRegistryFactory 中没有 getRegister 方法,进入父类 AbstractRegistryFactory 中找到 getRegister
registry = createRegistry(url); 跳转回 ZookeeperRegistryFactory 返回一个 ZookeeperRegistry,这里传入了一个zookeeperTransporter,是 injectExtension 注入
重新debug看看生成的类如下
public class ZookeeperTransporter$Adaptive implements org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter {
public org.apache.dubbo.remoting.zookeeper.ZookeeperClient connect(org.apache.dubbo.common.URL arg0) {
if (arg0 == null) throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg0;
String extName = url.getParameter("client", url.getParameter("transporter", "curator"));
if (extName == null)
throw new IllegalStateException("Failed to get extension (org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter) name from url (" + url.toString() + ") use keys([client, transporter])");
org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter extension = (org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter) ExtensionLoader.getExtensionLoader(org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter.class).getExtension(extName);
return extension.connect(arg0);
}
}
进入zookeeperRegistry,此时的url
zookeeper://192.168.50.135:2181/org.apache.dubbo.registry.RegistryService?application=springboot-dubbo-client&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=10016&qos.enable=false&release=2.7.3×tamp=1588131010498
根据url和上面商城的代码调用的是 curator
进入 CuratorZookeeperTransporter ,发现没有 connect() 方法,进入父类中找
AbstractZookeeperTransporter.connect()
new CuratorZookeeperClient(url)
key = zookeeper://192.168.50.135:2181/org.apache.dubbo.registry.RegistryService
进入CuratorZookeeperClient
client = builder.build();
这里已经进入了 curator 的 api 当中了
接着返回 RegistryProtocol 中,应为当前 protocol 已经是 zookeeper,所以会走else
进入doRefer方法
重点是 directory.subscribe 订阅监听
进入 RegistryDirectory 的subscribe
这里把 this 也就是 RegistryDirectory 传递了进去
这里的 registry 是 之前创建好的 ZookeeperRegistry 但是却没有该方法,找到其父类中该方法。
进入FailbackRegistry 的 subscribe方法
在FailbackRegistry 又调用子类
回到 ZookeeperRegistry ,if 条件不满足走else
toCategoriesPath(url) 是zk服务接口下面的三个地址,会分别做监听
然后在对子节点做监听 List<String> children = zkClient.addChildListener(path, zkListener);
重点关注 notify(url, listener, urls);,这里会对节点上的服务做感知
进入notify
进入父类 AbstractRegistry.notify
saveProperties(url); 会对服务地址做一个缓存,当zk挂了可以继续使用本地缓存
listener.notify(categoryList); 会拿到服务站的url地址做一个通知 , 也就是 RegistryDirectory的notify,这里会循环三次,只看service的url
overrideDirectoryUrl(); // 覆盖
refreshInvoker(urls); // 刷新Invoker,构建代理对象
注释也写得很清楚,将 url 转换为 invoker,重点在 toInvikers
urlInvokerMap = newUrlInvokerMap; urlInvokerMap是存放了所有服务地址的集合.
进入 toInvikers
重点在这句代码 invoker = new InvokerDelegate<>(protocol.refer(serviceType, url), url, providerUrl);
这里的 protocol 是一个自适应扩展点,根据当前的 url 协议是dubbo,最后会进入dubboProtocol,但是这不是一个单存的dubboProtocol,这个dubbo根据扩展点又被Wrapper所包装,
所以现在是InvokerDelegate(ProtocolFilterWrapper(ListenerInvokerWrapper(DubboInvoker)))
ProtocolFilterWrapper、ListenerInvokerWrapper 这两个类会构建一条调用链。
所以现在进入 DubboProtocol 中 ,进去后发现没有这个方法,按规矩找父类 AbstractProtocol
在接着进入DubboProtocol.protocolBindingRefer
InvokerDelegate(DubboInvoker)
进入 getClients(url)
进入 getSharedClient()
然后进入this.buildReferenceCountExchangeClientList
继续 clients.add(this.buildReferenceCountExchangeClient(url)); ExchangeClient exchangeClient = initClient(url);
进入client = Exchangers.connect(url, this.requestHandler);
private ExchangeClient initClient(URL url) {
String str = url.getParameter("client", url.getParameter("server", "netty"));
url = url.addParameter("codec", "dubbo");
url = url.addParameterIfAbsent("heartbeat", String.valueOf(60000));
if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) {
throw new RpcException("Unsupported client type: " + str + ", supported client type is " + StringUtils.join(ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions(), " "));
} else {
try {
Object client;
if (url.getParameter("lazy", false)) {
client = new LazyConnectExchangeClient(url, this.requestHandler);
} else {
client = Exchangers.connect(url, this.requestHandler);
}
return (ExchangeClient)client;
} catch (RemotingException var5) {
throw new RpcException("Fail to create remoting client for service(" + url + "): " + var5.getMessage(), var5);
}
}
}
这里个服务端注册一样,根据url拿到一个netty服务,把当前根据url构建好的服务封装到 ReferenceCountExchangeClient中返回。
这里到了 Exchangers 后面又是一个扩展点 ,跟服务发布的过程一样了,也是构建个netty服务
public static ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {
if (url == null) {
throw new IllegalArgumentException("url == null");
} else if (handler == null) {
throw new IllegalArgumentException("handler == null");
} else {
url = url.addParameterIfAbsent("codec", "exchange");
return getExchanger(url).connect(url, handler);
}
}
public static Exchanger getExchanger(URL url) {
String type = url.getParameter("exchanger", "header");
return getExchanger(type);
}
public static Exchanger getExchanger(String type) {
return (Exchanger)ExtensionLoader.getExtensionLoader(Exchanger.class).getExtension(type);
}
HeaderExchanger
public class HeaderExchanger implements Exchanger {
public static final String NAME = "header";
public HeaderExchanger() {
}
public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {
return new HeaderExchangeClient(Transporters.connect(url, new ChannelHandler[]{new DecodeHandler(new HeaderExchangeHandler(handler))}), true);
}
public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
return new HeaderExchangeServer(Transporters.bind(url, new ChannelHandler[]{new DecodeHandler(new HeaderExchangeHandler(handler))}));
}
}
Transporter
public static Client connect(URL url, ChannelHandler... handlers) throws RemotingException {
if (url == null) {
throw new IllegalArgumentException("url == null");
} else {
Object handler;
if (handlers != null && handlers.length != 0) {
if (handlers.length == 1) {
handler = handlers[0];
} else {
handler = new ChannelHandlerDispatcher(handlers);
}
} else {
handler = new ChannelHandlerAdapter();
}
return getTransporter().connect(url, (ChannelHandler)handler);
}
}
public static Transporter getTransporter() {
return (Transporter)ExtensionLoader.getExtensionLoader(Transporter.class).getAdaptiveExtension();
}
进入到netty了
public class NettyTransporter implements Transporter {
public static final String NAME = "netty";
public NettyTransporter() {
}
public Server bind(URL url, ChannelHandler listener) throws RemotingException {
return new NettyServer(url, listener);
}
public Client connect(URL url, ChannelHandler listener) throws RemotingException {
return new NettyClient(url, listener);
}
}
往前返回就会把一个带有netty服务的代理对象赋值给我们的接口类,当接口发起调用就会调用代理对象中的方法获得到方法名、参数值传递下去发起远程调用。
订阅完成之后会返回到 RegistryProtocol,后面会把这个包装过的directory返回给代理对象注入到我们引用的接口类中。
cluster = MockClusterInvoker(FailoverClusterInvoker(directory))