三、Dubbo注册心二---源码篇
Dubbo注册
zookeeper注册节点结构图
2.7.5版本前只有dubbo节点,2.7.5且之后 新增了services节点,并且之后版本会逐渐将dubbo剔除掉
这样的优势是将dubbo的结构下随着一个节点注册接口的增多,需要维护更多的节点变更,services结构是按照节点进行接口维护,减轻了zookeeper的节点压力,将计算压力放在了服务器上进行计算。
RegistryProtocol.export源码讲解
- org.apache.dubbo.registry.integration.RegistryProtocol#export
@Override
//第一次:
//originInvoker -> DelegateProviderMetaDataInvoker.class
//invoker -> eg: interface com.jiangzheng.course.dubbo.api.service.ServiceDemo -> service-discovery-registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?REGISTRY_CLUSTER=org.apache.dubbo.config.RegistryConfig&application=provider&client=curator&dubbo=2.0.2&pid=83877®istry=zookeeper&release=3.0.0.preview×tamp=1640763327339
//metadata -> eg: <dubbo:service beanName="serviceDemo" />
//第二次
//invoker -> eg: interface com.jiangzheng.course.dubbo.api.service.ServiceDemo -> registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=provider&client=curator&dubbo=2.0.2&pid=8093®istry=zookeeper&release=3.0.4×tamp=1640861452691
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
//获取注册中心地址
//eg1: service-discovery-registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?REGISTRY_CLUSTER=org.apache.dubbo.config.RegistryConfig&application=provider&client=curator&dubbo=2.0.2&pid=82721®istry=zookeeper&release=3.0.0.preview×tamp=1640760597729
//eg2: zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?REGISTRY_CLUSTER=org.apache.dubbo.config.RegistryConfig&application=provider&client=curator&dubbo=2.0.2&pid=83877&release=3.0.0.preview×tamp=1640763327339
URL registryUrl = getRegistryUrl(originInvoker);
// 获取服务要注册的接口协议信息
//eg: dubbo://30.96.216.200:20880/com.jiangzheng.course.dubbo.api.service.ServiceDemo?anyhost=true&application=provider&bind.ip=30.96.216.200&bind.port=29014&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.jiangzheng.course.dubbo.api.service.ServiceDemo&metadata-type=remote&methods=getName,getSelf&pid=82721&release=3.0.0.preview&side=provider×tamp=1640760597740
URL providerUrl = getProviderUrl(originInvoker);
//将dubbo协议的providerUrl转为provider协议的overrideSubscribeUrl
//eg: provider://30.96.216.200:20880/com.jiangzheng.course.dubbo.api.service.ServiceDemo?anyhost=true&application=provider&bind.ip=30.96.216.200&bind.port=29014&category=configurators&check=false&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.jiangzheng.course.dubbo.api.service.ServiceDemo&metadata-type=remote&methods=getName,getSelf&pid=83877&release=3.0.0.preview&side=provider×tamp=1640763327347
final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl);
final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
Map<URL, NotifyListener> overrideListeners = getProviderConfigurationListener(providerUrl).getOverrideListeners();
overrideListeners.put(registryUrl, overrideSubscribeListener);
//对providerUrl没有做处理,更像是一个预留
//eg: dubbo://30.96.216.200:20880/com.jiangzheng.course.dubbo.api.service.ServiceDemo?anyhost=true&application=provider&bind.ip=30.96.216.200&bind.port=29014&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.jiangzheng.course.dubbo.api.service.ServiceDemo&metadata-type=remote&methods=getName,getSelf&pid=82721&release=3.0.0.preview&side=provider×tamp=1640760597740
providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener);
//暴露一个本地服务 Netty -> consumer
final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker, providerUrl);
// 获取到一个具体的Registry(服务发现注册的)客户端
final Registry registry = getRegistry(registryUrl);
//做provider url的转化
//eg: dubbo://30.96.216.200:29014/com.jiangzheng.course.dubbo.api.service.ServiceDemo?anyhost=true&application=provider&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.jiangzheng.course.dubbo.api.service.ServiceDemo&metadata-type=remote&methods=getName,getSelf&pid=83877&release=3.0.0.preview&side=provider×tamp=1640763327347
final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl);
// 是否延迟发布
boolean register = providerUrl.getParameter(REGISTER_KEY, true);
if (register) {
//服务提供者开始注册节点
register(registry, registeredProviderUrl);
}
// 修改状态
registerStatedUrl(registryUrl, registeredProviderUrl, register);
//将ProviderUrl和SubscribeUrl在本地做一个暴露
exporter.setRegisterUrl(registeredProviderUrl);
exporter.setSubscribeUrl(overrideSubscribeUrl);
if (!registry.isServiceDiscovery()) {
// 2.6.x版本前 用来做通知
registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
}
//空的方法实现,用户可通过SPI自定义实现
notifyExport(exporter);
//返回一个exporter
return new DestroyableExporter<>(exporter);
}
- 核心代码
- final ExporterChangeableWrapper exporter = doLocalExport(originInvoker, providerUrl); //本地服务JMI的暴露
- final Registry registry = getRegistry(registryUrl); //获取注册服务
- register(registry, registeredProviderUrl); //进行注册
RegistryProtocol.register源码讲解
- org.apache.dubbo.registry.integration.RegistryProtocol#register
在讲解前补充下上一方法export的相关内容,export会被调用两回,一回是在zookeeper下注册services节点,一回是注册dubbo节点,具体该注册哪一个节点呢,这个和registryUrl的内容有关。在示例中也有标识eg1、eg2,二者的协议不同,eg1的url是service-discovery-registry协议,eg2的url是zookeeper协议。
//org.apache.dubbo.registry.integration.RegistryProtocol#export中调用
//url是service-discovery-registry协议的返回registry -> ServiceDiscoveryRegistry(ZookeeperServiceDiscovery) 可查看图1了解具体结构
//url是zookeeper协议的返回registry -> ZookeeperRegistry 可查看图2了解具体结构
final Registry registry = getRegistry(registryUrl);
if (register) {
register(registry, registeredProviderUrl);
}
//org.apache.dubbo.registry.integration.RegistryProtocol#register
private void register(Registry registry, URL registeredProviderUrl) {
registry.register(registeredProviderUrl);
}
//org.apache.dubbo.registry.ListenerRegistryWrapper#register
@Override
public void register(URL url) {
try {
//url是service-discovery-registry协议的 走ServiceDiscoveryRegistry,此处不会立即触发注册,具体下面有解释
//url是zookeeper协议的 走ZookeeperRegistry
registry.register(url);
} finally {
if (CollectionUtils.isNotEmpty(listeners) && !UrlUtils.isConsumer(url)) {
RuntimeException exception = null;
for (RegistryServiceListener listener : listeners) {
if (listener != null) {
try {
listener.onRegister(url, registry);
} catch (RuntimeException t) {
logger.error(t.getMessage(), t);
exception = t;
}
}
}
if (exception != null) {
throw exception;
}
}
}
}
- 看ServiceDiscoveryRegistry的调用 — zookeeper中注册services节点
@Override
public final void register(URL url) {
if (!shouldRegister(url)) { // Should Not Register
return;
}
doRegister(url);
}
@Override
public void doRegister(URL url) {
url = addRegistryClusterKey(url);
if (writableMetadataService.exportURL(url)) {
if (logger.isInfoEnabled()) {
logger.info(format("The URL[%s] registered successfully.", url.toString()));
}
} else {
if (logger.isWarnEnabled()) {
logger.warn(format("The URL[%s] has been registered.", url.toString()));
}
}
}
貌似没有做对应的节点注册,其实注册并没有放在此处来完成,这里有必要解释下,Dubbo的启动是由SpringBoot的事件监听来驱动的,而此处的RegistryProtocol#export方法调用是由方法exportServices()调用完成,下一步会调用registerServiceInstance()方法, 关于zk上/services节点注册就是放在registerServiceInstance()中做的,具体可查看如下方法调用流程,具体代码省略了,只列出了方法调用。(不同版本实现类有所不同,可通过方法名进行定位所在类)
3.0.0.preview版本调用链路
-
org.springframework.context.support.AbstractApplicationContext#refresh
-
org.springframework.context.support.AbstractApplicationContext#finishRefresh
-
org.springframework.context.support.AbstractApplicationContext#publishEvent(org.springframework.context.ApplicationEvent)
-
org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, org.springframework.core.ResolvableType)
-
org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
-
org.springframework.context.event.SimpleApplicationEventMulticaster#invokeListener
-
org.springframework.context.event.SimpleApplicationEventMulticaster#doInvokeListener
-
org.apache.dubbo.config.spring.context.OneTimeExecutionApplicationContextEventListener#onApplicationEvent
-
org.apache.dubbo.config.spring.context.DubboBootstrapApplicationListener#onApplicationContextEvent
-
org.apache.dubbo.config.spring.context.DubboBootstrapApplicationListener#onContextRefreshedEvent
-
org.apache.dubbo.config.bootstrap.DubboBootstrap#start
-
org.apache.dubbo.config.bootstrap.DubboBootstrap#registerServiceInstance
-
org.apache.dubbo.config.bootstrap.DubboBootstrap#doRegisterServiceInstance
-
org.apache.dubbo.registry.client.EventPublishingServiceDiscovery#register
-
org.apache.dubbo.registry.client.EventPublishingServiceDiscovery#executeWithEvents
-
org.apache.dubbo.registry.zookeeper.ZookeeperServiceDiscovery#register
3.0.4版本调用链路
- org.springframework.context.support.AbstractApplicationContext#refresh
- org.springframework.context.support.AbstractApplicationContext#finishRefresh
- org.springframework.context.support.AbstractApplicationContext#publishEvent(org.springframework.context.ApplicationEvent)
- org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, org.springframework.core.ResolvableType)
- org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
- org.springframework.context.event.SimpleApplicationEventMulticaster#invokeListener
- org.springframework.context.event.SimpleApplicationEventMulticaster#doInvokeListener
- org.apache.dubbo.config.spring.context.DubboDeployApplicationListener#onApplicationEvent
- org.apache.dubbo.config.spring.context.DubboDeployApplicationListener#onContextRefreshedEvent
- org.apache.dubbo.config.deploy.DefaultModuleDeployer#start
- org.apache.dubbo.config.deploy.DefaultApplicationDeployer#prepareApplicationInstance
- org.apache.dubbo.config.deploy.DefaultApplicationDeployer#registerServiceInstance
- org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils#registerMetadataAndInstance
- org.apache.dubbo.registry.client.AbstractServiceDiscovery#register
- org.apache.dubbo.registry.zookeeper.ZookeeperServiceDiscovery#doRegister
在ZookeeperServiceDiscovery的doRegister或register(版本不同)中有调用build(serviceInstance)方法,build方法构建了节点中保存的json内容,并返回一个org.apache.curator.x.discovery.ServiceInstance<ZookeeperInstance>实例
- 看ZookeeperRegistry的调用 — zookeeper中注册dubbo节点
- org.apache.dubbo.registry.ListenerRegistryWrapper#register
- org.apache.dubbo.registry.support.FailbackRegistry#register
- org.apache.dubbo.registry.zookeeper.ZookeeperRegistry#doRegister
@Override
public void doRegister(URL url) {
try {
checkDestroyed();
//调用zk客户端进行创建节点
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);
}
}
private String toUrlPath(URL url) {
//此处会对节点名称进行encode
return toCategoryPath(url) PATH_SEPARATOR URL.encode(url.toFullString());
}
//此处采用递归的方式进行节点创建
@Override
public void create(String path, boolean ephemeral) {
if (!ephemeral) {
if (persistentExistNodePath.contains(path)) {
return;
}
if (checkExists(path)) {
persistentExistNodePath.add(path);
return;
}
}
//获取最后一个“/”的位置
int i = path.lastIndexOf('/');
if (i > 0) {
//如果path中还存在“/”字符,则继续递归调用该方法
create(path.substring(0, i), false);
}
//如果不存在“/”字符了,则表示 当前获取到了根路径名称,递归创建之后的路径即可
if (ephemeral) {
createEphemeral(path);
} else {
createPersistent(path);
persistentExistNodePath.add(path);
}
}
该递归创建zk节点的编程方式 还是值得我们学习一下。
值得一提的是dubbo的SPI,对于程序中具体使用实体类的指定都是依赖于SPI
例如:/org/apache/dubbo/dubbo/3.0.4/dubbo-3.0.4.jar!/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscovery的文件内容如下
file=org.apache.dubbo.registry.client.FileSystemServiceDiscovery
multicast=org.apache.dubbo.registry.multicast.MulticastServiceDiscovery
zookeeper=org.apache.dubbo.registry.zookeeper.ZookeeperServiceDiscovery
nacos=org.apache.dubbo.registry.nacos.NacosServiceDiscovery
multiple=org.apache.dubbo.registry.multiple.MultipleServiceDiscovery
kubernetes=org.apache.dubbo.registry.kubernetes.KubernetesServiceDiscovery
dns=org.apache.dubbo.registry.dns.DNSServiceDiscovery
xds=org.apache.dubbo.registry.xds.XdsServiceDiscovery
或
/org/apache/dubbo/dubbo/3.0.4/dubbo-3.0.4.jar!/META-INF/dubbo/internal/org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter
curator=org.apache.dubbo.remoting.zookeeper.curator.CuratorZookeeperTransporter
curator5=org.apache.dubbo.remoting.zookeeper.curator5.Curator5ZookeeperTransporter
里面定义了对应的实现
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgcbjjc
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01