该文章内容发布已经超过一年,请注意检查文章中内容是否过时。
上个博客《15-Dubbo的三大中心之元数据中心源码解析》导出服务端的时候多次提到了元数据中心,注册信息的注册。 Dubbo3出来时间不太长,对于现在的用户来说大部分使用的仍旧是Dubbo2.x, Dubbo3 比较有特色也是会直接使用到的功能就是应用级服务发现:
对于直接使用Dubbo3的用户还好,可以仅仅开启应用级注册,但是对于Dubbo2.x的用户升级到Dubbo3的用户来说前期都是要开启双注册来慢慢迁移的,既注册传统的接口信息到注册中心,又注册应用信息到注册中心,同时注册应用与接口关系的元数据信息。 关于双注册与服务迁移的过程的使用可以参考官网: 应用级地址发现迁移指南
关于官网提供者双注册的图我这里贴一下,方便了解:
这个配置的解析过程在前面的博客介绍元数据中心的时候很详细的说了相关链接:15-Dubbo的三大中心之元数据中心源码解析
对应代码位于:DefaultApplicationDeployer类型的startMetadataCenter()方法
具体逻辑是这个方法: useRegistryAsMetadataCenterIfNecessary
关于元数据中心地址的获取,主要经过如下逻辑:
MetadataReportConfig 映射就是获取需要的配置。
最后会把查询到的元数据中心配置存储在配置缓存中方便后续使用。
双注册配置类型是这个
默认值为all代表应用级注册和接口级注册,当前在完全迁移到应用级注册之后可以将服务直接迁移到应用级配置上去。 配置值解释:
后面的代码如果想要看更详细的代码可以看博客《16-模块发布器发布服务全过程》 关于这个配置的使用我们详细来看下,在Dubbo服务注册时候会先通过此配置查询需要注册服务地址,具体代码位于ServiceConfig的doExportUrls()方法中:
然后就是具体注册中心地址的获取过程我们看下: ConfigValidationUtils的加载注册中心地址方法loadRegistries
ConfigValidationUtils的双注册地址的获取genCompatibleRegistries方法. 前面代码获取到了一个注册中心地址列表例如:
下面可以看下如果根据配置来转换为应用级注册地址+接口级注册地址
可以看到这里简化的配置比较容易理解了
这个方法是根据服务注册模式来判断使用接口级注册地址还是应用级注册地址分别如下所示: 配置信息: dubbo.application.register-mode 配置值:
最终的注册地址配置如下: 接口级注册地址:
应用级注册地址:
前面说了这个注册服务的配置地址会由Dubbo内部进行判断如果判断是all的话会自动将一个配置的注册地址转变为两个一个是传统的接口级注册,一个是应用级注册使用的配置地址
然后我们先看注册中心,注册服务数据的源码
如果想要查看源码细节可以在RegistryProtocol类型的export(final Invoker
RegistryProtocol的export方法的注册中心注册数据代码如下:
在上个博客中我们整体说了下服务注册时候的一个流程,关于数据向注册中心的注册细节这里可以详细看下
前面的代码使用url来获取注册中心操作对象如下调用代码:
对应代码如下:
关于参数URL有两个在前面已经说过,url信息如下:
接口级注册地址:
应用级注册地址:
注册中心工厂对象与注册中心操作对象的获取与执行我们通过Debug来看比较麻烦,这里涉及到很多扩展机制动态生成的代码我们无法看到,这里我直接来贴一下比较关键的一些类型,以Zookeeper注册中心来举例子:
先来看下注册工厂相关的类型:
接下来看封装了注册中心操作逻辑的注册中心领域对象:
了解了这几个领域对象这里我们回到代码逻辑,这里直接看将会执行的一些核心逻辑:
前面注册中心工厂不论那种协议的地址信息获取到的都是一个RegistryFactory$Adaptive类型(由扩展机制的字节码工具自动生成的代码)
如果getRegistry参数为应用级注册地址。如下所示将获取到的类型为ServiceDiscoveryRegistryFactory逻辑来获取注册中心: (这个逻辑是@Adaptive注解产生的了逻辑具体原理可以看扩展机制中@Adaptive的实现)
getRegistry方法优先走的逻辑是这里:AbstractRegistryFactory模板类型中的getRegistry方法
逻辑其实吧比较简单,概括下上面的逻辑:
上面比较重要的逻辑是createRegistry这个
整个调用过程我给大家看下Debug的详情,这里很多逻辑由扩展机制产生的这里直接看下逻辑调用栈,有几个需要关注的地方我圈了起来:
我们继续看服务发现的注册中心工厂对象的获取,代码如下:
ServiceDiscoveryRegistryFactory类型的createRegistry方法
通过以上代码可以看到其实最终创建的是一个ServiceDiscoveryRegistry注册中心对象,这个url协议被转换为了对应注册中心的协议,也就是说双注册会有两个协议一个是原先的接口级注册注册中心对象(这个还未说到)和这里对应注册中心协议的服务发现注册中心对象ServiceDiscoveryRegistry
ServiceDiscoveryRegistry服务发现注册中心对象的初始化过程:
ServiceDiscoveryRegistry中创建服务发现对象createServiceDiscovery方法
ServiceDiscoveryRegistry中创建服务发现对象getServiceDiscovery方法
ServiceDiscoveryFactory和ServiceDiscovery类型可以往后看
参数url如下所示:
在前面我们看到了RegistryProtocol中调用register来注册服务提供者的数据到注册的中心,接下来详细看下实现原理: 下面参数为ServiceDiscoveryRegistry为情况下举例子:ServiceDiscoveryRegistry类型的register方法与ZookeeperRegister注册不一样传统的接口级注册在这个方法里面就将服务数据注册到注册中心了,服务发现的数据注册分为了两步,这里仅仅将数据封装到内存中如下: url例子为:
RegistryProtocol中的register方法:
上面这个代码会优先走ListenerRegistryWrapper的一些逻辑来执行register方法来触发一些监听器的逻辑,我们直接跳到ServiceDiscoveryRegistry中的register方法来看
ServiceDiscoveryRegistry的register方法
ServiceDiscoveryRegistry的doRegister方法:
AbstractServiceDiscovery的register方法:
MetadataInfo 类型的addService方法
前面我们通过服务发现的的url进行了举例子,其实在RegistryProtocol协议的export方法中还会注册接口级信息: 例如如下关键代码: 当registryUrl参数不是服务发现协议service-discovery-registry配置而是zookeeper如下时候获取到的扩展类型将是与Zookeeper相关的扩展对象
RegistryProtocol协议的export方法中接口级数据注册的核心代码如下: 如下代码的操作类型可以看注释
如上代码是获取Zookeeper操作对象和向Zookeeper中写入服务提供者信息的代码,关于与Zookeeper连接和注册数据本地缓存的代码可以看ZookeeperRegistry类型和它的几个父类型比如:CacheableFailbackRegistry类型,关于接口级数据的注册可以看register方法,这个就不详细说了,下面我贴一下接口级数据注册的Zookeeper信息可以了解下就行:
接口信息如下,上面我们需要注意的是这个 url配置为临时节点,当与Zookeeper断开连接或者Session超时的时候这个信息会被移除:
在说这个实现之前我们先看看相关类型,这个服务发现相关的类型与注册中心相关的类型有点类似:
服务发现工厂类型:
服务发现类型:
刚刚在 ServiceDiscoveryRegistry中创建服务发现对象getServiceDiscovery方法看到了两个类型一个是服务发现工厂类型ServiceDiscoveryFactory,一个是服务发现类型ServiceDiscovery
AbstractServiceDiscoveryFactory类型的getServiceDiscovery方法
createDiscovery方法对应ZookeeperServiceDiscoveryFactory类型中的createDiscovery方法
如下代码所示:
ZookeeperServiceDiscovery的构造器
这个方法比较重要是应用级服务发现的实现,这里主要关注下serviceDiscovery类型的创建与启动,这个应用级服务发现的实现其实是Dubbo使用了Curator来做的,Dubbo只是在这里封装了一些方法来进行调用Curator的实现: 关于Curator的官方文档可以看curator官网
关于Zookeeper上面注册服务应用级服务注册信息可以看如下图所示(后面会具体讲到数据注册时的调用):
我这个服务提供者注册的应用数据如下:
如果感兴趣的话可以看更详细的curator服务发现文档curator-x-discovery
重载的构造器
服务映射主要是通过服务名字来反查应用信息的应用名字如下图所示
这里我们来看下服务映射相关的类型主要通过如下代码来获取扩展对象:
对应类型如下:
最终获取的扩展实现类型为:MetadataServiceNameMapping 构造器如下:
服务映射元数据父类型AbstractServiceNameMapping如下:
前面注册数据的时候并没有把服务配置的元数据直接注册在注册中心而是需要在导出服务之后在ServiceConfig中来发布元数据,这个就需要我们回到ServiceConfig的exportUrl方法来看了如下所示:
在exportRemote之后单独调用发布元数据的方法来发布,通过调用元数据工具类来发布元数据信息接下来我们详细看下: MetadataUtils类型的publishServiceDefinition方法:
AbstractMetadataReport的storeProviderMetadata方法如下所示:
AbstractMetadataReport的存储元数据方法storeProviderMetadataTask
元数据信息如下:可以分为两类 应用元数据,服务元数据
Zookeeper扩展类型ZookeeperMetadataReport实现的存储方法如下所示doStoreProviderMetadata:
如果我们自己实现一套元数据就可以重写这个方法来进行元数据的额存储
ZookeeperMetadataReport的doStoreProviderMetadata
ZookeeperMetadataReport的storeMetadata
原文地址:17-Dubbo服务提供者的双注册原理