Dubbo服务导出字面意思就是,把生产者的服务,注册到注册中心。加了@Service注解的服务可以被理解为Dubbo的一种服务,这些服务会被转化成ServiceBean(父类是ServiceConfig),一个服务对应一个ServiceBean,里面包装的参数会在dubbo中被解析成一个个Url然后上传到注册中心中去;所以Dubbo服务导出需要考虑以下几个问题
1.服务导出是在什么时候
2.Dubbo底层是netty,是怎么启动的
3.该如何将Url注册到注册中心
4.如果注册中心上的数据发生变更又该如何监听
@Service中可以配置一些参数,以此来确定一个服务,配置参数也不仅仅是通过这个方法,还可以通过在VmOptions中通过-D配置(系统环境变量),dubbo.properties文件,或者Dubbo自己所属的动态配置中心,可以通过这四种方法去确定服务的配置,这些配置如果配置了同一个参数,也有优先级
以下是通过这四种方式确定参数的优先级以及这四种方式在Dubbo中对应的实现类
![d3bdf27a5e1d4ca8b31e68a5d7187d50.png](https://i-blog.csdnimg.cn/blog_migrate/8b2b3e3d38938576dd71a3abc405fe6e.png)
![1edae58b0b1246dd8f889d1d93b0d5b1.png](https://i-blog.csdnimg.cn/blog_migrate/03274ddcc99003b4b299d0cf9a93a60b.png)
![05d4be9ed69544bb8f3d62ec951ffdca.png](https://i-blog.csdnimg.cn/blog_migrate/7e84655c1ea568364cf66755a55fdf6d.png)
dubbo.registries.r1.address=zookeeper://127.0.0.1:2181
dubbo.registries.r1.timeout=3000
registries就是上面对应的配置dubbo.registries后面跟着的数量,你配了几个就是几个,然后就会解析这些参数放到一个map里面,最后就是调用parseURLs(address,map),根据你传入的map来构造注册中心的地址(REGISTRY_URL),最后就是放到一个List中然后返回
registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-provider1application&dubbo=2.0.2&logger=log4j&pid=10920®istry=zookeeper&release=2.7.0&timeout=3000×tamp=1703071491179
providerUrl:dubbo://172.16.5.151:20880/org.apache.dubbo.demo.DemoService?anyhost=true&application=dubbo-demo-provider1-application&bean.name=ServiceBean:org.apache.dubbo.demo.DemoService:1.0.1:tulings&bind.ip=172.16.5.151&bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&group=tulings&interface=org.apache.dubbo.demo.DemoService&logger=log4j&methods=sayHello&pid=10920&release=2.7.0&revision=1.0.1&side=provider×tamp=1703071655680&version=1.0.1
![851c1d32ca03474fb71cee4209f4a627.png](https://i-blog.csdnimg.cn/blog_migrate/811012e4823656783a7ba836c89bfcc1.png)
![b03889f63b6f4e729629cde0ce2262e6.png](https://i-blog.csdnimg.cn/blog_migrate/255ebe9584ee2858cff8c6e1f49dcebb.png)
invoker.getUrl():registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-provider1-application&dubbo=2.0.2&export=dubbo://172.16.5.151:20880/org.apache.dubbo.demo.DemoService?anyhost=true&application=dubbo-demo-provider1-application&bean.name=ServiceBean:org.apache.dubbo.demo.DemoService:1.0.1:tulings&bind.ip=172.16.5.151&bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&group=tulings&interface=org.apache.dubbo.demo.DemoService&logger=log4j&methods=sayHello&pid=10920&release=2.7.0&revision=1.0.1&side=provider×tamp=1703071655680&version=1.0.1&logger=log4j&pid=10920®istry=zookeeper&release=2.7.0&timeout=3000×tamp=1703071491179
![a4d44d470b714917b19544d39554e079.png](https://i-blog.csdnimg.cn/blog_migrate/e72ee072dd08bcc342ba05ab00601a67.png)
![ac65b209eef345bdbb3ed612d575cce4.png](https://i-blog.csdnimg.cn/blog_migrate/b33f5d5c6d9385cb3d43de9948f440e0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/aef441528225b8826516995f26302f03.png)
![45633b99ae2449b98edb314e6d823cd5.png](https://i-blog.csdnimg.cn/blog_migrate/be03680790e9b251e5dd711d6ed5137f.png)
![ffd0303c9c1b4663b15a843ff32890b4.png](https://i-blog.csdnimg.cn/blog_migrate/62c8dbba03d337f8eb091ad37168b987.png)
重写url:在overrideUrlWithConfig这个方法里会利用providerConfigurationListener和serviceConfigurationListener去重写providerUrl
providerConfigurationListener表示应用级别的动态配置监听器,
serviceConfigurationListener表示服务级别的动态配置监听器
可以看到服务级别的重写会覆盖应用级别的覆盖(因为写在最后一行)
因为应用监听是在属性那边就直接初始化好了,所以不需要再去初始化一遍,这边直接来看服务监听,可以看到调用了initWith方法并且传入了一个path进去(就是我们监听数据变化的地址)
在initWith方法中,便可看到为这个路径添加了监听器(this),所以数据有变动的时候便会触发到你自己本身的ServiceConfigurationListener.notifyOverrides()->RegistryProtocol.doOverrideIfNecessary()然后去重写Invoker重写推送数据至注册中心
启动netty服务
doLocalExport方法下面就会根据你传进来的invokerDelegate.getUrl()中的protocol协议去调用对应的export方法
然后之前的步骤会先根据invoker造出一个exporter,后续调用的时候就可以直接从本地缓存拿,然后接着就会开启openServer下的createSever方法
开启Netty服务的链路比较长,这边就用调用链来代替:
server = Exchangers.bind(url, requestHandler)->HeaderExchanger.bind(URL url, ExchangeHandler handler)->Transporters.bind(URL url, ChannelHandler... handlers)->NettyTransporter.bind(URL url, ChannelHandler listener)->NettyServer.super()->AbstractServer.doOpen()->NettyServer.doOpen():最终启动Netty服务
启动netty服务之后便会调用register(URL registryUrl, URL registeredProviderUrl)->FailbackRegistry.doRegister()->ZookeeperRegistry.doRegister()去注册数据,最后存到注册中心的url是简化后的registeredProviderUrl,而不是整个registryUrl和providerUrl拼起来的,因为有很多参数是不需要的或者重复的,这段简化的url逻辑在RegistryProtocol.getRegisteredProviderUrl(providerUrl, registryUrl)中体现