首先分享之前的所有文章 , 欢迎点赞收藏转发三连下次一定 >>>> ???
文章合集 : ? juejin.cn/post/694164…
Github : ? github.com/black-ant
CASE 备份 : ? gitee.com/antblack/ca…
一 . 前言
服务发现的作用主要范围包括向注册中心注册服务 , 以及服务的发现 (Feign 的负载均衡是在 Client 端做的 , 猜测Dubbo负载均衡也是)
Dubbo 提供多种注册中心 , 常见的有 Nacos , Zookeeper 和 Redis , 此篇也只看看3种
二 . 服务发现流程
2.1 服务发现的调用逻辑
// 服务发现的起点还是 BootStrap , 由 Listener 发起流程
C- DubboBootstrapApplicationListener # onContextRefreshedEvent
C- DubboBootstrap # start : 开始初始化
C- DubboBootstrap # exportServices : 注册 DubboService
C- ServiceConfig # export : 调用init 执行初始化 , 校验 config , 设置 serviceMetadata 元数据
C- ServiceConfig # doExport : 没太多逻辑 , 下层调用而已
C- ServiceConfig # doExportUrls : ServiceRepository 进行保存和下层调用
C- ServiceConfig # doExportUrlsFor1Protocol
C- ProtocolFilterWrapper # export
C- ProtocolListenerWrapper # export
C- RegistryProtocol # export : 发起注册逻辑
复制代码
Zookeeper Service 详情
{
"name": "dubbo-demo-annotation-provider",
"id": "10.10.100.140:20880",
"address": "10.10.100.140",
"port": 20880,
"sslPort": null,
"payload": {
"@class": "org.apache.dubbo.registry.zookeeper.ZookeeperInstance",
"id": null,
"name": "dubbo-demo-annotation-provider",
"metadata": {
"REGISTRY_CLUSTER": "registryConfig",
"anyhost": "true",
"application": "dubbo-demo-annotation-provider",
"deprecated": "false",
"dubbo": "2.0.2",
"dubbo.endpoints": "[{\"port\":20880,\"protocol\":\"dubbo\"}]",
"dubbo.metadata-service.url-params": "{\"version\":\"1.0.0\",\"dubbo\":\"2.0.2\",\"port\":\"20880\",\"protocol\":\"dubbo\"}",
"dubbo.metadata.revision": "3c1be7b82505c5da23a5bc1cd1211417",
"dubbo.metadata.storage-type": "local",
"dynamic": "true",
"generic": "false",
"interface": "org.apache.dubbo.demo.DemoService",
"metadata-type": "remote",
"methods": "sayHello,sayHelloAsync",
"pid": "21576",
"release": "",
"side": "provider",
"timestamp": "1626856228483"
}
},
"registrationTimeUTC": 1626856236245,
"serviceType": "DYNAMIC",
"uriSpec": null
}
复制代码
Zookeeper 中数据情况
2.2 调用的起点
C- DubboBootstrap # start
C- DubboBootstrap # exportServices : start 逻辑中发起 export 处理
private void exportServices() {
// Step 1 : configManager.getServices() 获取 Service 列表 -> PRO00001
for (ServiceConfigBase sc : configManager.getServices()) {
// 获取当前 ServiceConfig , 并且为其设置容器
ServiceConfig<?> serviceConfig = (ServiceConfig<?>) sc;
serviceConfig.setBootstrap(this);
if (!serviceConfig.isRefreshed()) {
// 需要刷新时对其进行刷新
serviceConfig.refresh();
}
// 需要异步处理 -> export-async
if (sc.shouldExportAsync()) {
// 明显看到这里使用 ScheduledExecutorService + future 发起了异步调用
ExecutorService executor = executorRepository.getExportReferExecutor();
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
if (!sc.isExported()) {
sc.export();
exportedServices.add(sc);
}
} catch (Throwable t) {
logger.error("export async catch error : " + t.getMessage(), t);
}
}, executor);
asyncExportingFutures.add(future);
} else {
// 这里逻辑都是一样的 , 没有导出过的进行导出 ,同时添加到对应集合中
if (!sc.isExported()) {
sc.export();
exportedServices.add(sc);
}
}
}
}
// PRO00001 : configManager.getServices 列表
<dubbo:service path="org.apache.dubbo.demo.DemoService" ref="org.apache.dubbo.demo.provider.DemoServiceImpl@60990e5c" generic="false" deprecated="false" dynamic="true" id="ServiceBean:org.apache.dubbo.demo.DemoService" />
复制代码
补充 configManager
该方法从configsCache 中获取对应的参数 ,此处取得是 service
添加的流程 :
- C- AbstractConfig # addIntoConfigManager -> org.apache.dubbo.config.spring.ServiceBean
- C- ConfigManager # addConfig : 添加 Config , 用于前文循环时使用
可以看到 , 第一步时使用的就是 serverBean , 这个Bean 在扫描时创建 , 详见 -> Dubbo 3.0 : DubboService 的扫描
2.3 解析出 Service
中间没有太多东西 , 主要调用流程为 :
- C- ServiceConfig # export :
- C- ServiceConfig # doExport :
- C- ServiceConfig # doExportUrls :
- C- ServiceConfig # exported :
// 在此阶段 , 构建出 Registry URL , 用于 Zookeeper 注册
private void doExportUrls() {
// PRO0001 :
ServiceRepository repository = ApplicationModel.getServiceRepository();
// PRO0002 :
ServiceDescriptor serviceDescriptor = repository.registerService(getInterfaceClass());
repository.registerProvider(
getUniqueServiceName(),
ref,
serviceDescriptor,
this,
serviceMetadata
);
// PRO0003 :
List<URL> registryURLs = ConfigValidationUtils.loadRegistries(this, true);
// PRO0004 :
for (ProtocolConfig protocolConfig : protocols) {
// org.apache.dubbo.demo.DemoService
String pathKey = URL.buildKey(getContextPath(protocolConfig)
.map(p -> p + "/" + path)
.orElse(path), group, version);
// 如果用户指定了路径,则再次注册服务,将其映射到路径
repository.registerService(pathKey, interfaceClass);
doExportUrlsFor1Protocol(protocolConfig, registryURLs);
}
}
// PRO0001 : ServiceRepository 结构
{
"services": {
"serviceName": "org.apache.dubbo.rpc.service.EchoService",
"serviceName": "org.apache.dubbo.rpc.service.GenericService",
"serviceName": "org.apache.dubbo.monitor.MetricsService",
"serviceName": "org.apache.dubbo.monitor.MonitorService",
"serviceName": "org.apache.dubbo.demo.DemoService",
},
"providers": {
"org.apache.dubbo.demo.DemoService": "ProviderModel"
},
"providersWithoutGroup": "org.apache.dubbo.demo.DemoService:0.0.0"
}
// PRO0003 : 构建 RegistryURL
service-discovery-registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?REGISTRY_CLUSTER=registryConfig&application=dubbo-demo-annotation-provider&dubbo=2.0.2&pid=28256®istry=zookeeper×tamp=1626858537404
registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?REGISTRY_CLUSTER=registryConfig&application=dubbo-demo-annotation-provider&dubbo=2.0.2&pid=28256®istry=zookeeper×tamp=1626858537404
复制代码
2.4 执行主流程
其中主步骤分为 3 步 :
- Step 1 : 属性准备
- Step 2 : 获取 host port , 构建 url
- Step 3 : 构建 Invoke , export 导出
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
String name = protocolConfig.getName();
if (StringUtils.isEmpty(name)) {
name = DUBBO;
}
// Step 1 : 属性准备
Map<String, String> map = new HashMap<String, String>();\
// String PROVIDER_SIDE = "provider";
// String SIDE_KEY = "side";
map.put(SIDE_KEY, PROVIDER_SIDE);
// 此环节添加属性
ServiceConfig.appendRuntimeParameters(map);
AbstractConfig.appendParameters(map, getMetrics());
AbstractConfig.appendParameters(map, getApplication());
AbstractConfig.appendParameters(map, getModule());
// remove 'default.' prefix for configs from ProviderConfig
// appendParameters(map, provider, Constants.DEFAULT_KEY);
AbstractConfig.appendParameters(map, provider);
AbstractConfig.appendParameters(map, protocolConfig);
AbstractConfig.appendParameters(map, this);
MetadataReportConfig metadataReportConfig = getMetadataReportConfig();
if (metadataReportConfig != null && metadataReportConfig.isValid()) {
map.putIfAbsent(METADATA_KEY, REMOTE_METADATA_STORAGE_TYPE);
}
if (CollectionUtils.isNotEmpty(getMethods())) {
//TODO Improve method config processing
//... 此处如果 dubbo:method 进行了方法级处理 , 此处会深入处理 , 同样是添加 method 处理
}
if (ProtocolUtils.isGeneric(generic)) {
map.put(GENERIC_KEY, generic);
map.put(METHODS_KEY, ANY_VALUE);
} else {
String revision = Version.getVersion(interfaceClass, version);
if (revision != null && revision.length() > 0) {
map.put(REVISION_KEY, revision);
}
String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
// ["sayHello","sayHelloAsync"]
if (methods.length == 0) {
// 省略为空逻辑
} else {
map.put(METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
}
}
// 提供程序配置的令牌值用于将值分配给ServiceConfig#令牌
if (ConfigUtils.isEmpty(token) && provider != null) {
token = provider.getToken();
}
if (!ConfigUtils.isEmpty(token)) {
if (ConfigUtils.isDefault(token)) {
map.put(TOKEN_KEY, UUID.randomUUID().toString());
} else {
map.put(TOKEN_KEY, token);
}
}
// 讲所有的 map 放入 元数据中
serviceMetadata.getAttachments().putAll(map);
// Step 2 : 获取 host port , 构建 url
String host = findConfigedHosts(protocolConfig, registryURLs, map);
Integer port = findConfigedPorts(protocolConfig, name, map);
// PRO24001 -> url
URL url = new ServiceConfigURL(name, null, null, host, port, getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), map);
// 自定义Configurator以附加额外参数
if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
.hasExtension(url.getProtocol())) {
url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
.getExtension(url.getProtocol()).getConfigurator(url).configure(url);
}
String scope = url.getParameter(SCOPE_KEY);
// don't export when none is configured
if (!SCOPE_NONE.equalsIgnoreCase(scope)) {
// 如果配置不是远程的,则导出到本地
if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) {
exportLocal(url);
}
// 如果配置不是本地的,则导出到远程
if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {
if (CollectionUtils.isNotEmpty(registryURLs)) {
// PIC24002 -> registryURLs
for (URL registryURL : registryURLs) {
//if protocol is only injvm ,not register
if (LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
continue;
}
url = url.addParameterIfAbsent(DYNAMIC_KEY, registryURL.getParameter(DYNAMIC_KEY));
URL monitorUrl = ConfigValidationUtils.loadMonitor(this, registryURL);
if (monitorUrl != null) {
url = url.putAttribute(MONITOR_KEY, monitorUrl);
}
// For providers, this is used to enable custom proxy to generate invoker
String proxy = url.getParameter(PROXY_KEY);
if (StringUtils.isNotEmpty(proxy)) {
registryURL = registryURL.addParameter(PROXY_KEY, proxy);
}
// Step 3 : 构建 Invoke , export 导出
Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryURL.putAttribute(EXPORT_KEY, url));
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
// -> 2.5 Protocol 注册
Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);
exporters.add(exporter);
}
} else {
if (MetadataService.class.getName().equals(url.getServiceInterface())) {
MetadataUtils.saveMetadataURL(url);
}
Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, url);
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);
exporters.add(exporter);
}
MetadataUtils.publishServiceDefinition(url);
}
}
this.urls.add(url);
}
复制代码
PRO24001 案例 : providerUrl
dubbo://192.168.181.2:20880/org.apache.dubbo.demo.DemoService
?anyhost=true
&application=dubbo-demo-annotation-provider
&bind.ip=192.168.181.2
&bind.port=20880
&deprecated=false
&dubbo=2.0.2
&dynamic=true
&generic=false
&interface=org.apache.dubbo.demo.DemoService
&metadata-type=remote
&methods=sayHello,sayHelloAsync
&pid=17324
&release=
&side=provider
×tamp=1628690334012
复制代码
PRO24002 案例 : registryUrl
service-discovery-registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService
?REGISTRY_CLUSTER=registryConfig
&application=dubbo-demo-annotation-provider
&dubbo=2.0.2
&pid=17324
®istry=zookeeper
×tamp=1628690331733
复制代码
PIC24002
2.5 传入代理类
在这一步构建了 url ,同时生成了 ServiceDiscoveryRegistry
C- RegistryProtocol
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
// service-discovery-registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService....
URL registryUrl = getRegistryUrl(originInvoker);
// dubbo://192.168.181.2:20880/org.apache.dubbo.demo.DemoService?anyhost=true....
URL providerUrl = getProviderUrl(originInvoker);
// PRO0003 : URL 参数
final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl);
final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
// 重写 URL
providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener);
//export invoker
final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker, providerUrl);
// Step 3 : 通过 Registry Factory 获取使用的 Registry , 例如 : ZookeeperRegistry -> 3.1
final Registry registry = getRegistry(registryUrl);
// Step 4 : 构建注册对象 -> PRO0003
final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl);
// Step 5 : 注册发布服务
boolean register = providerUrl.getParameter(REGISTER_KEY, true);
if (register) **{**
// -> 2.5.2 Registry 的管理
register(registry, registeredProviderUrl);
}
// 在提供程序模型上注册声明的url
registerStatedUrl(registryUrl, registeredProviderUrl, register);
exporter.setRegisterUrl(registeredProviderUrl);
exporter.setSubscribeUrl(overrideSubscribeUrl);
// Deprecated! Subscribe to override rules in 2.6.x or before.
registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
notifyExport(exporter);
//Ensure that a new exporter instance is returned every time export
return new DestroyableExporter<>(exporter);
}
// PRO0003 : URL 参数
provider://192.168.181.2:20880/org.apache.dubbo.demo.DemoService
?anyhost=true
&application=dubbo-demo-annotation-provider
&bind.ip=192.168.181.2
&bind.port=20880
&category=configurators
&check=false
&deprecated=false
&dubbo=2.0.2
&dynamic=true
&generic=false
&interface=org.apache.dubbo.demo.DemoService
&metadata-type=remote
&methods=sayHello,sayHelloAsync
&pid=17324
&release=
&side=provider
×tamp=1628690334012
复制代码
Registry 可以分为以下几个部分 :
- 由 getRegistry 发起获取 Registry
- createRegistry 发起创建逻辑
- RegistryProtocol 调用 doRegister 执行 Register
三 . Registry 的创建
共用流程
// Step 1 : 获取 Registry
C- RegistryFactoryWrapper
public Registry getRegistry(URL url) {
return new ListenerRegistryWrapper(registryFactory.getRegistry(url),
Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(RegistryServiceListener.class)
.getActivateExtension(url, "registry.listeners")));
}
// Step 2 : 调用工厂创建 registry
C- AbstractRegistryFactory
public Registry getRegistry(URL url) {
Registry defaultNopRegistry = getDefaultNopRegistryIfDestroyed();
if (null != defaultNopRegistry) {
return defaultNopRegistry;
}
url = URLBuilder.from(url)
.setPath(RegistryService.class.getName())
.addParameter(INTERFACE_KEY, RegistryService.class.getName())
.removeParameters(EXPORT_KEY, REFER_KEY, TIMESTAMP_KEY)
.build();
String key = createRegistryCacheKey(url);
// 上锁
LOCK.lock();
try {
//..........
// Map<String, Registry> REGISTRIES = new HashMap<>();
Registry registry = REGISTRIES.get(key);
if (registry != null) {
return registry;
}
//通过 spi/ioc 的方式获取 Registry -> org.apache.dubbo.registry.client.ServiceDiscoveryRegistry
registry = createRegistry(url);
// 放入缓存
REGISTRIES.put(key, registry);
return registry;
} finally {
// Release the lock
LOCK.unlock();
}
}
复制代码
3.1 创建 ServiceDiscoveryRegistry
// Step 3 : ServiceDiscoveryRegistryFactory
protected Registry createRegistry(URL url) {
if (UrlUtils.hasServiceDiscoveryRegistryProtocol(url)) {
// 此处拿到的为 zookeeper
String protocol = url.getParameter(REGISTRY_KEY, DEFAULT_REGISTRY);
// zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?REGISTRY_CLUSTER=registryConfig&application=dubbo-demo-annotation-provider&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=2816
url = url.setProtocol(protocol).removeParameter(REGISTRY_KEY);
}
return new ServiceDiscoveryRegistry(url);
}
public ServiceDiscoveryRegistry(URL registryURL) {
this.registryURL = registryURL;
this.serviceDiscovery = createServiceDiscovery(registryURL);
this.writableMetadataService = WritableMetadataService.getDefaultExtension();
}
// 下次调用 ,
protected ServiceDiscovery createServiceDiscovery(URL registryURL) {
ServiceDiscovery serviceDiscovery = getServiceDiscovery(registryURL);
execute(() -> {
// 初始化操作
serviceDiscovery.initialize(registryURL.addParameter(INTERFACE_KEY, ServiceDiscovery.class.getName())
.removeParameter(REGISTRY_TYPE_KEY));
});
return serviceDiscovery;
}
static WritableMetadataService getDefaultExtension() {
return getExtensionLoader(WritableMetadataService.class).getDefaultExtension();
}
复制代码
3.2 创建 ZookeeperRegistry
Zookeeper 只是 Dubbo 支持的注册中心之一 , 以其为例看一下创建和使用流程 :
这里有一个核心点 , ZookeeperRegistry 的创建是在 , 它创建时会被包裹为一个 ListenerRegistryWrapper 对象
C- ZookeeperRegistryFactory
public Registry createRegistry(URL url) {
return new ZookeeperRegistry(url, zookeeperTransporter);
}
// 创建 ZookeeperRegistry
public ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter) {
super(url);
if (url.isAnyHost()) {
throw new IllegalStateException("registry address == null");
}
String group = url.getGroup(DEFAULT_ROOT);
if (!group.startsWith(PATH_SEPARATOR)) {
group = PATH_SEPARATOR + group;
}
this.root = group;
zkClient = zookeeperTransporter.connect(url);
zkClient.addStateListener((state) -> {
if (state == StateListener.RECONNECTED) {
ZookeeperRegistry.this.fetchLatestAddresses();
} else if (state == StateListener.NEW_SESSION_CREATED) {
try {
ZookeeperRegistry.this.recover();
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
} else if (state == StateListener.SESSION_LOST) {
} else if (state == StateListener.SUSPENDED) {
} else if (state == StateListener.CONNECTED) {
}
});
}
C- ExtensionLoader
private T createExtension(String name, boolean wrap) {
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null || unacceptableExceptions.contains(name)) {
throw findException(name);
}
try {
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.getDeclaredConstructor().newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
injectExtension(instance);
if (wrap) {
List<Class<?>> wrapperClassesList = new ArrayList<>();
if (cachedWrapperClasses != null) {
wrapperClassesList.addAll(cachedWrapperClasses);
wrapperClassesList.sort(WrapperComparator.COMPARATOR);
Collections.reverse(wrapperClassesList);
}
if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
for (Class<?> wrapperClass : wrapperClassesList) {
Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
if (wrapper == null
|| (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
}
}
initExtension(instance);
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
type + ") couldn't be instantiated: " + t.getMessage(), t);
}
}
复制代码
补充 : ListenerRegistryWrapper
可以看到 , 这里 ListenerRegistryWrapper 中包含了一个 Registry 对象
public class ListenerRegistryWrapper implements Registry {
private static final Logger logger = LoggerFactory.getLogger(ListenerRegistryWrapper.class);
private final Registry registry;
private final List<RegistryServiceListener> listeners;
}
复制代码
四 . Registry 的调用
Registry 在 RegistryProtocol # register 进行注册 , 会调用父类 FailbackRegistry , 最终调用各种的实现类
FailbackRegistry 通用处理
// 此处以 FailbackRegistry 为例
public void register(URL url) {
if (!acceptable(url)) {
return;
}
super.register(url);
removeFailedRegistered(url);
removeFailedUnregistered(url);
try {
// Sending a registration request to the server side
doRegister(url);
} catch (Exception e) {
// 省略部分异常处理逻辑
// Record a failed registration request to a failed list, retry regularly
addFailedRegistered(url);
}
}
复制代码
4.1 ServiceDiscoveryRegistry 注册
// Step 1 : 发起 Registry
C- RegistryProtocol
private void register(Registry registry, URL registeredProviderUrl) {
registry.register(registeredProviderUrl);
}
C- ServiceDiscoveryRegistry
public final void register(URL url) {
if (!shouldRegister(url)) { // Should Not Register
return;
}
doRegister(url);
//--> url = addRegistryClusterKey(url); 其中调用 addRegistryClusterKey
}
// Step 2 : 获取 RegistryClusterKey
private URL addRegistryClusterKey(URL url) {
String registryCluster = serviceDiscovery.getUrl().getParameter(REGISTRY_CLUSTER_KEY);
if (registryCluster != null && url.getParameter(REGISTRY_CLUSTER_KEY) == null) {
url = url.addParameter(REGISTRY_CLUSTER_KEY, registryCluster);
}
// dubbo://192.168.181.2:20880/org.apache.dubbo.demo.DemoService?REGISTRY_CLUSTER=registryConfig&anyhost=true&application=dubbo-demo-annotation-provider&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&metadata-type=remote&methods=sayHello,sayHelloAsync&pid=13200&release=&side=provider×tamp=1626146555672
return url;
}
// Step 3 : doRegister 进行注册
public void doRegister(URL url) {
url = addRegistryClusterKey(url);
// 其中主要是对 Map 进行操作
// ConcurrentNavigableMap<String, SortedSet<URL>> exportedServiceURLs = new ConcurrentSkipListMap<>();
if (writableMetadataService.exportURL(url)) {
} else {
}
}
复制代码
4.2 ZookeeperRegistry 注册
public void doRegister(URL url) {
try {
zkClient.create(toUrlPath(url), url.getParameter(DYNAMIC_KEY, true));
} catch (Throwable e) {
throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
}
}
复制代码
五 . 补充深入
5.1 服务注册器的选择
// Dubbo 提供了 Zookeeper , Nacos 等多个服务注册器 , 这里来看一下此处是如何选择的 , 此处以 Nacos 为例
// 环节一 : 判断是否支持 Nacos ExtensionLoader
C- DubboBootstrap
private boolean isUsedRegistryAsCenter(RegistryConfig registryConfig, Supplier<Boolean> usedRegistryAsCenter,
String centerType,
Class<?> extensionClass) {
final boolean supported;
Boolean configuredValue = usedRegistryAsCenter.get();
if (configuredValue != null) { // If configured, take its value.
supported = configuredValue.booleanValue();
} else { // Or check the extension existence
String protocol = registryConfig.getProtocol();
supported = supportsExtension(extensionClass, protocol);
}
return supported;
}
C- DubboBootstrap
private boolean supportsExtension(Class<?> extensionClass, String name) {
if (isNotEmpty(name)) {
ExtensionLoader extensionLoader = getExtensionLoader(extensionClass);
return extensionLoader.hasExtension(name);
}
return false;
}
// 环节二 : 获取 ExtensionLoader
复制代码
Nacos 请求逻辑
// 调用逻辑
C- DubboBootstrapApplicationListener # onApplicationContextEvent
C- DubboBootstrapApplicationListener # onContextRefreshedEvent
C- DubboBootstrap # start
C- DubboBootstrap # exportServices
C- ServiceConfig # export + doExport + doExportUrlsFor1Protocol : 从配置中获取URL
C- RegistryProtocol # export
C- NacosNamingService # getAllInstances
C- NamingGrpcClientProxy # subscribe
C- NamingGrpcClientProxy # requestToServer
复制代码
Zookeeper 请求逻辑
// 调用逻辑
C- CuratorZookeeperClient.<init>
C- CuratorZookeeperTransporter.createZookeeperClient
C- AbstractZookeeperTransporter.connect
C- ZookeeperTransporter$Adaptive.connect
C- ZookeeperDynamicConfiguration.<init>
C- ZookeeperDynamicConfigurationFactory.createDynamicConfiguration
C- AbstractDynamicConfigurationFactory.getDynamicConfiguration
C- DynamicConfiguration.getDynamicConfiguration
C- DubboBootstrap.prepareEnvironment
C- DubboBootstrap.startConfigCenter
C- DubboBootstrap.initialize
C- DubboBootstrap.start
C- DubboBootstrapApplicationListener.onContextRefreshedEvent
C- DubboBootstrapApplicationListener.onApplicationContextEvent
复制代码
总结 :
ServiceDiscoveryRegistry 这一块没深入太多 , 后面有时间再看看 , 下面来看一下完整的流程图