远程暴露有两种情况:
具体步骤如下:
和本地暴露的区别:
包含两个步骤:服务导出和服务注册
// NOTE1: 创建Invoker
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
// NOTE: DelegateProviderMetaDataInvoker 用于持有 Invoker 和 ServiceConfig
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
// NOTE2: 导出服务,并生成 Exporter
Exporter<?> exporter = protocol.export(wrapperInvoker);
registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.2&......&pid=10421&qos.port=22222®istry=zookeeper×tamp=1561639865358
路径:由两个小链路构成一个大链路
1、RegistryProtocol
//☆☆--RegistryProtocol
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
// NOTE: 获取注册中心 URL
URL registryUrl = getRegistryUrl(originInvoker);
//NOTE: 服务暴露URL
URL providerUrl = getProviderUrl(originInvoker);
//NOTE: 获取订阅 URL(provider开头)
final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl);
//NOTE: 使用 OverrideListener 对象,订阅配置规则
final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener);
//NOTE 1: 创建Exporter,暴露服务
final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker, providerUrl);
// NOTE: 根据 URL 加载 Registry 实现类,比如 ZookeeperRegistry(这里不是SPI 机制)
final Registry registry = getRegistry(originInvoker);
// NOTE: 获取已注册的服务提供者 URL
final URL registeredProviderUrl = getRegisteredProviderUrl(providerUrl, registryUrl);
//NOTE: 向本地注册表,注册服务提供者
ProviderInvokerWrapper<T> providerInvokerWrapper = ProviderConsumerRegTable.registerProvider(originInvoker,
registryUrl, registeredProviderUrl);
//to judge if we need to delay publish
boolean register = registeredProviderUrl.getParameter("register", true);
if (register) {
// NOTE 2: 向注册中心注册服务
register(registryUrl, registeredProviderUrl);
providerInvokerWrapper.setReg(true);
}
exporter.setRegisterUrl(registeredProviderUrl);
exporter.setSubscribeUrl(overrideSubscribeUrl);
// NOTE 3: 创建并返回 DestroyableExporter
return new DestroyableExporter<>(exporter);
}
2、RegistryProtocol.doLocalExport
/**
* 服务导出
*/
private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker, URL providerUrl) {
//NOTE:缓存
String key = getCacheKey(originInvoker);
ExporterChangeableWrapper<T> exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
if (exporter == null) {
synchronized (bounds) {
exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
if (exporter == null) {
//NOTE:创建 Invoker 为委托类对象,将providerUrl和originInvoker封装
final Invoker<?> invokerDelegete = new InvokerDelegate<T>(originInvoker, providerUrl);
//NOTE: DubboProtocol export创建Exporter,进行服务暴露
/**
* 使用【创建的 Exporter 对象】+【originInvoker】,创建 ExporterChangeableWrapper 对象。这样,originInvoker 就和 Exporter 对象,形成了绑定的关系
*/
exporter = new ExporterChangeableWrapper<T>((Exporter<T>) protocol.export(invokerDelegete), originInvoker);
bounds.put(key, exporter);
}
}
}
return exporter;
}
3、DubboProtocol.export(invokerDelegete)
//☆☆--DubboProtocol
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
//对应的是providerUrl
URL url = invoker.getUrl();
// NOTE: 获取服务标识,由服务组名,服务名,服务版本号以及端口组成
String key = serviceKey(url);
//NOTE 1: 创建DubboExporter对象
DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
// NOTE: 将 键值对放入缓存中
exporterMap.put(key, exporter);
......
// NOTE 2 : 启动服务器(netty 通讯)
openServer(url);
// NOTE 3: 优化序列化
optimizeSerialization(url);
return exporter;
}
private void openServer(URL url) {
// NOTE: 取 host:port,并将其作为服务器实例的 key,用于标识当前的服务器实例。在同一台机器上,同一个端口上仅允许启动一个服务器实例。
String key = url.getAddress();
boolean isServer = url.getParameter(Constants.IS_SERVER_KEY, true);
if (isServer) {
ExchangeServer server = serverMap.get(key);
if (server == null) {
synchronized (this) {
server = serverMap.get(key);
if (server == null) {
serverMap.put(key, createServer(url));
}
}
} else {
server.reset(url);
}
}
}
/**
* NOTE: 创建通信服务器(服务层)
* 1、检测是否存在 server 参数所代表的 Transporter 拓展,不存在则抛出异常
* 2、创建ExchangerServer服务器实例
* 3、检测是否支持 client 参数所表示的 Transporter 拓展
*/
private ExchangeServer createServer(URL url) {
url = url.addParameterIfAbsent(Constants.CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString());
//NOTE: 添加心跳检测配置到 url 中,默认60秒
url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT));
// NOTE: 获取 server 参数,默认为 netty
String str = url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_SERVER);
// NOTE: 通过 SPI 检测是否存在 server 参数所代表的 Transporter 拓展,不存在则抛出异常
......代码省略
// NOTE: 添加编码解码器参数(默认为'dubbo')
url = url.addParameter(Constants.CODEC_KEY, DubboCodec.NAME);
ExchangeServer server;
try {
//NOTE: 创建ExchangerServer服务器
server = Exchangers.bind(url, requestHandler);
} catch (RemotingException e) {
throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
}
//是否支持 client 参数所表示的 Transporter 拓展
......省略client的校验代码
return server;
}
//☆☆--Exchangers
public static ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
url = url.addParameterIfAbsent(Constants.CODEC_KEY, "exchange");
//获得Exchanger的扩展实现类:HeaderExchanger
Exchanger exchanger = ExtensionLoader.getExtensionLoader(Exchanger.class).getExtension(type);
return exchanger.bind(url, handler);
}
//☆☆--HeaderExchanger
public class HeaderExchanger implements Exchanger {
@Override
public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
// NOTE: 这里包含了多个调用,分别如下:
// 1. 创建 HeaderExchangeHandler 对象
// 2. 创建 DecodeHandler 对象
// 3. 通过 Transporters 构建 Server 实例(默认NettyServer,NettyTransporter)
// 4. 创建 HeaderExchangeServer 对象
return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
}
}
//☆☆--Transporters
public static Server bind(URL url, ChannelHandler... handlers) throws RemotingException {
if (handlers.length == 1) {
handler = handlers[0];
} else {//如果 handlers 元素数量大于1,则创建 ChannelHandler 分发器
handler = new ChannelHandlerDispatcher(handlers);
}
// NOTE: 获取自适应 Transporter 实例,并调用实例方法(默认为NettyTransporter)
return getTransporter().bind(url, handler);
}
//☆☆--NettyTransporter
public class NettyTransporter implements Transporter {
@Override
public Server bind(URL url, ChannelHandler listener) throws RemotingException {
// NOTE: 创建Netty Server 并调用内部的doOpen()方法启动服务
return new NettyServer(url, listener);
}
}
调用DubboProtocol创建Exporter后,会根据
exporter = new ExporterChangeableWrapper<T>((Exporter<T>) protocol.export(invokerDelegete), originInvoker);
根据registryUrl获取对应的Registry扩展类(以ZookeeperRegistry为例)
//RegistryProtocol
Registry registry = registryFactory.getRegistry(registryUrl);
//根据registryUrl获得对应的Registry:ZookeeperRegistry、DubboRegistry等
private Registry getRegistry(final Invoker<?> originInvoker) {
URL registryUrl = getRegistryUrl(originInvoker);
return registryFactory.getRegistry(registryUrl);
}
//☆☆--AbstractRegistryFactory
public Registry getRegistry(URL url) {
url = url.setPath(RegistryService.class.getName())
.addParameter(Constants.INTERFACE_KEY, RegistryService.class.getName())
.removeParameters(Constants.EXPORT_KEY, Constants.REFER_KEY);
String key = url.toServiceStringWithoutResolving();
// 创建Registry时,需要加锁
LOCK.lock();
try {
Registry registry = REGISTRIES.get(key);
if (registry != null) {
return registry;
}
//创建Registry
registry = createRegistry(url);
if (registry == null) {
throw new IllegalStateException("Can not create registry " + url);
}
REGISTRIES.put(key, registry);
return registry;
} finally {
// Release the lock
LOCK.unlock();
}
}
public class ZookeeperRegistryFactory extends AbstractRegistryFactory {
private ZookeeperTransporter zookeeperTransporter;
public void setZookeeperTransporter(ZookeeperTransporter zookeeperTransporter) {
this.zookeeperTransporter = zookeeperTransporter;
}
@Override
public Registry createRegistry(URL url) {
//创建ZookeeperRegistry(内部默认的zkClient为:CuratorZookeeperClient)
return new ZookeeperRegistry(url, zookeeperTransporter);
}
}
注册中心注册服务其实就是将服务提供者的信息,封装到URL中,在注册中心(zk)上创建一个个节点。
public void register(URL registryUrl, URL registeredProviderUrl) {
Registry registry = registryFactory.getRegistry(registryUrl);
// 注册服务
registry.register(registeredProviderUrl);
}
//☆☆---ZookeeperRegistry
public void doRegister(URL url) {
try {
// NOTE: 通过 Zookeeper 客户端创建节点,节点路径由 toUrlPath 方法生成,路径格式如下:
// ${group}/${serviceInterface}/providers/${url}
// NOTE: 比如: /dubbo/org.apache.dubbo.DemoService/providers/dubbo%3A%2F%2F127.0.0.1....
zkClient.create(toUrlPath(url), url.getParameter(Constants.DYNAMIC_KEY, true));
} catch (Throwable e) {
throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
}
}
//AbstractZookeeperClient
public void create(String path, boolean ephemeral) {
if (!ephemeral) {
if (checkExists(path)) {
return;
}
}
//NOTE: 层层解析,创建zk节点
int i = path.lastIndexOf('/');
if (i > 0) {
create(path.substring(0, i), false);
}
//NOTE: 是否创建临时节点
if (ephemeral) {
createEphemeral(path);
} else {
createPersistent(path);
}
}
//CuratorZookeeperClient
public void createEphemeral(String path) {
try {
// 通过 Curator 框架创建节点
client.create().withMode(CreateMode.EPHEMERAL).forPath(path);
} catch (NodeExistsException e) {
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
服务远程暴露,创建Invoker简单,但后续的服务导出流程比较长,主要在创建Exporter和服务注册过程很复杂。而且在RegistryProtocol和DubboProtocol执行逻辑中,都会用类似ProtocolFilterWrapper或者ProtocolListenerWrapper这种封装类来实现AoP增加一些功能。在服务注册过中,路径特别深,有一些我还没有深入,比如ExchangerServer的创建、Transporter的创建、Registry的创建细节。理解服务远程暴露主要包含:
RegistryProtocol内部注入的属性:RegistryFactory、Cluster
package org.apache.dubbo.registry;
import org.apache.dubbo.common.extension.ExtensionLoader;
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(
"Fail 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);
}
}
package org.apache.dubbo.rpc.cluster;
import org.apache.dubbo.common.extension.ExtensionLoader;
public class Cluster$Adaptive implements org.apache.dubbo.rpc.cluster.Cluster {
public org.apache.dubbo.rpc.Invoker join(org.apache.dubbo.rpc.cluster.Directory arg0)
throws org.apache.dubbo.rpc.RpcException {
if (arg0 == null) {
throw new IllegalArgumentException(
"org.apache.dubbo.rpc.cluster.Directory argument == null");
}
if (arg0.getUrl() == null) {
throw new IllegalArgumentException(
"org.apache.dubbo.rpc.cluster.Directory argument getUrl() == null");
}
org.apache.dubbo.common.URL url = arg0.getUrl();
String extName = url.getParameter("cluster", "failover");
if (extName == null) {
throw new IllegalStateException(
"Fail to get extension(org.apache.dubbo.rpc.cluster.Cluster) name from url(" +
url.toString() + ") use keys([cluster])");
}
org.apache.dubbo.rpc.cluster.Cluster extension = (org.apache.dubbo.rpc.cluster.Cluster) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.cluster.Cluster.class).getExtension(extName);
return extension.join(arg0);
}
}