美文网首页dubbo
Dubbo之服务导出源码分析

Dubbo之服务导出源码分析

作者: loveFXX | 来源:发表于2020-07-27 10:56 被阅读0次

    要了解服务导出做了什么,需要了解导出的目的是什么?
    dubbo是一款面向接口代理的高性能RPC调用,说白了就是提供远程服务。


    image.png

    服务导出需要做的:简单说就是根据服务参数、服务协议构建服务URL,注册到注册中心,并启动Server。其中服务参数可以动态配置也需要监听。

    服务导出入口

    1、onApplicationEvent
    org.apache.dubbo.config.spring.ServiceBean#onApplicationEvent
    发布ContextRefreshedEvent,进行导出服务


    image.png

    2、export
    org.apache.dubbo.config.spring.ServiceBean#export
    调用父类ServiceConfig导出,之后发布一个ServiceBeanExportedEvent


    image.png
    3、export
    org.apache.dubbo.config.ServiceConfig#export
    image.png
    ①、检查更新配置参数

    ②、shouldExport检查服务是否需要导出
    org.apache.dubbo.config.ServiceConfig#shouldExport


    image.png
    ③、shouldDelay检查服务是否需要延迟发布
    image.png
    image.png
    ④、doExport进行服务导出

    更新配置

    checkAndUpdateSubConfigs

    org.apache.dubbo.config.ServiceConfig#checkAndUpdateSubConfigs


    image.png

    1、completeCompoundConfigs
    ServiceConfig中的某些属性如果是空的,那么就从ProviderConfig、ModuleConfig、ApplicationConfig中获取
    ①、如果配置了ProviderConfig provider,如果application、module、registries、monitor、protocols、configCenter这些属性为空的情况下,可以从provider中获取信息并赋值


    image.png
    ②、同样的道理,如果ModuleConfig module不为空,可以为registries、monitor为空的赋值
    image.png

    ③、如果ApplicationConfig application不为空,可以为registries、monitor为空的赋值
    2、startConfigCenter
    从配置中心获取配置,包括应用配置和全局配置


    image.png
    ①、如果ConfigCenterConfig ConfigCenter配置中心配置不为空,则需要从其他位置获取配置中心的相关属性信息进行更新refresh
    org.apache.dubbo.config.AbstractConfig#refresh
    image.png
    a、前缀是prefix = "dubbo.config-center"、id = null 在不同的位置获取混合的配置CompositeConfiguration
    image.png
    CompositeConfiguration是一个有序的LinkedList
    SystemConfiguration(JVM环境变量系统配置)、EnvironmentConfiguration(操作系统环境变量)、InmemoryConfiguration(配置中心应用配置和全局配置)、PropertiesConfiguration(dubbo.properties中的配置)
    b、根据configCenterFirst配置设置config的位置。默认true第四个位置
    image.png
    参数配置及优先级

    SystemConfiguration:是系统环境变量,可以在服务启动时通过-D指定参数
    AbstractConfig:是通过@Service注解配置的参数
    PropertiesConfiguration:是dubbo.properties文件配置的
    AppExternalConfiguration和ExternalConfiguration:是在配置中心Dubbo-Admin中配置的,AppXxx是应用级别
    配置优先级是:SystemConfiguration -> AppExternalConfiguration -> ExternalConfiguration -> AbstractConfig -> PropertiesConfiguration
    如果放到第二个位置优先级是:SystemConfiguration -->AbstractConfig -> AppExternalConfiguration -> ExternalConfiguration -> -> PropertiesConfiguration
    c、根据setXX()方法和setParameters()方法进行参数值覆盖


    image.png

    ②、prepareEnvironment
    管理台上的动态配置中心,如果是zookeeper,获取的就是/dubbo/config/dubbo/dubbo.properties节点中的内容。如果是应用级别的则获取的就是/dubbo/config/dubbo-demo-consumer-application/dubbo.properties节点中的内容(dubbo-demo-consumer-application应用名,这里是以dubbo-demo为例)


    image.png
    ③、refreshAll
    ConfigManager.getInstance().refreshAll()刷新所有配置
    org.apache.dubbo.config.context.ConfigManager#refreshAll
    image.png
    3、checkDefault 从配置中心设置Provider配置
    org.apache.dubbo.config.ServiceConfig#checkDefault
    image.png
    image.png

    4、checkProtocol 从配置中心设置Protocol配置


    image.png
    org.apache.dubbo.config.ServiceConfig#convertProtocolIdsToProtocols
    image.png
    ①、从配置中心的全局配置获取dubbo.protocols.的配置项值添加到configedProtocols
    ②、从配置中心的应用配置获取dubbo.protocols.的配置项值添加到configedProtocols
    ③、用,号join所有的protocol(configedProtocols),并赋值给protocolIds
    image.png
    ④、如果protocolIds为空,说明配置中心没有配置协议,就取默认的协议
    ⑤、如果配置中心配置协议(protocolIds不为空),就把从配置中心配置的协议添加到服务的协议列表中
    5、checkApplication
    如果ApplicationConfig为空,则构造一个ApplicationConfig
    image.png
    6、checkRegistry
    如果协议不是injvm本地协议(isOnlyInJvm),则会从配置中心获取Registry配置
    image.png
    7、refresh 刷新配置中心配置
    image.png
    8、checkMetadataReport 更新MetadataReportConfig中的属性为优先级最高的配置
    image.png
    9、检查当前服务是不是一个泛化服务
    image.png

    10、Local、Stub、Mock
    local和stub一样,不建议使用了。如果Local存根为true,则存根类为interfaceName + "Local"。如果Stub本地存根为true,则存根类为interfaceName + "Stub"


    image.png
    image.png
    a、checkStubAndLocal
    org.apache.dubbo.config.AbstractInterfaceConfig#checkStubAndLocal
    image.png
    b、checkMock
    image.png

    服务导出

    doExport

    org.apache.dubbo.config.ServiceConfig#doExport


    image.png

    unexported表示:当前服务已经被取消了,就不需要再导出了
    exported表示:已经导出了,就不再重复导出了
    1、doExportUrls
    org.apache.dubbo.config.ServiceConfig#doExportUrls


    image.png
    ①、registryURLs
    注册服务也是一个服务,也会有对应的url,通过调用该url可以完成服务注册
    registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-provider1-application&dubbo=2.0.2&logger=log4j&pid=3384&registry=zookeeper&release=2.7.0&timestamp=1595994447689
    

    ②、遍历protocols协议
    pathKey = group/应用名/path服务名:version
    例如:mygroup/dubbo-demo/org.apache.dubbo.demo.DemoService:1.0.1
    ProviderMethodModel表示某一个方法、方法名所属的服务的,包含实现类,接口,以及接口中的各个方法


    image.png

    ApplicationModel表示应用中有哪些服务提供者和引用了哪些服务
    每种协议都会导出一个单独的服务,并注册到各个注册中心
    2、doExportUrlsFor1Protocol
    org.apache.dubbo.config.ServiceConfig#doExportUrlsFor1Protocol


    image.png
    image.png
    protocolConfig表示协议配置,registryURLs表示所有的注册中心URL
    ①、如果配置的协议没有配置name,则默认为dubbo
    ②、map表示服务url的参数,包括监控中心、应用、模块、提供者、协议、 服务本身
    image.png

    ③、methods方法参数处理


    image.png
    ④、METHODS_KEY = methods 参数添加
    image.png
    ⑤、Token参数
    是为了防止服务被消费者直接调用(伪造http请求)
    image.png
    ⑥、获取服务URL 可以通过获取的host和port访问该服务
    image.png
    服务url
    dubbo://192.168.7.81:20881/org.apache.dubbo.demo.DemoService?anyhost=true&application=dubbo-demo-provider1-application&bean.name=ServiceBean:org.apache.dubbo.demo.DemoService&bind.ip=192.168.7.81&bind.port=20881&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&logger=log4j&methods=sayHello&pid=3384&release=2.7.0&side=provider&timestamp=1595995315282
    

    ⑦、scope导出方式(scope=null进行远程导出)

    image.png
    scope取值是:null、remote、 local、none
    如果scope为none,则不会进行任何的服务导出,既不会远程,也不会本地
    如果scope不是remote,则会进行本地导出,会把当前url的protocol改为injvm,然后进行导出
    如果scope不是local,则会进行远程导出
    如果是injvm,则不需要进行注册中心注册
    ⑧、为服务url添加dynamic、monitor、proxy参数,如果存在的话
    如果有注册中心,则将服务注册到注册中心
    image.png
    ⑨、生成Invoker代理对象
    image.png
    Invoker 是实体域,它是 Dubbo 的核心模型,它代表一个可执行体,可向它发起 invoke 调用。可参考官网架构设计领域模型
    a、生成一个当前服务接口的代理对象invoker。使用代理(默认使用javassist)生成一个Invoker,Invoker表示服务提供者的代理,可以使用Invoker的invoke方法执行服务
    参数包含:服务的实现者ref=DemoServiceImpl、服务接口类interfaceClass=DemoService、服务的注册地址url是
    registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-provider1-application&dubbo=2.0.2&export=dubbo%3A%2F%2F192.168.7.81%3A20881%2Forg.apache.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddubbo-demo-provider1-application%26bean.name%3DServiceBean%3Aorg.apache.dubbo.demo.DemoService%26bind.ip%3D192.168.7.81%26bind.port%3D20881%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26generic%3Dfalse%26interface%3Dorg.apache.dubbo.demo.DemoService%26logger%3Dlog4j%26methods%3DsayHello%26pid%3D4824%26release%3D2.7.0%26side%3Dprovider%26timestamp%3D1596073850978&logger=log4j&pid=4824&registry=zookeeper&release=2.7.0&timestamp=1596073850955 
    

    生成的注册服务URL是在registryURL和export参数是服务url的拼装
    b、DelegateProviderMetaDataInvoker也表示服务提供者,包括了Invoker和服务的配置。是对Invoker的包裹
    c、protocol.export(wrapperInvoker)这是导出的核心,使用了SPI。
    使用特定的协议来对服务进行导出,这里的协议是registry,导出成功后得到一个Exporter
    由于注册地址也是服务,所以会先使用RegistryProtocol进行服务注册(服务导出),然后注册(服务导出)完了之后,再使用DubboProtocol进行导出
    自适应SPI会获取url
    org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker#getUrl


    image.png

    ⑩、当存在注册中心时,是先使用Registy协议注册服务,然后在使用Http协议导出服务。而没有注册中心时,是直接使用Http协议导出服务。根据服务url,讲服务的元信息存入元数据中心MetadataReportService

    export

    RegistryProtocol被ProtocolFilterWrapper包裹,ProtocolFilterWrapper被ProtocolListenerWrapper包裹(SPI原理)

    RegistryProtocol

    1、export
    org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper#export
    如果协议是REGISTRY_PROTOCOL(registry)则会直接走到下一个protocol实现类ProtocolFilterWrapper。
    如果不是则会使用ListenerExporterWrapper处理

    image.png
    2、export
    org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper#export
    ProtocolFilterWrapper导出同样的道理,如果是registry则会直接走到下一个。如果不是,则会调用buildInvokerChain构建执行代理链
    image.png
    3、export
    org.apache.dubbo.registry.integration.RegistryProtocol#export
    image.png
    ①、获取registryUrl 将registry://xxx?xx=xx&registry=zookeeper 转为 zookeeper://xx
    zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-provider1-application&dubbo=2.0.2&export=dubbo%3A%2F%2F192.168.7.81%3A20881%2Forg.apache.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddubbo-demo-provider1-application%26bean.name%3DServiceBean%3Aorg.apache.dubbo.demo.DemoService%26bind.ip%3D192.168.7.81%26bind.port%3D20881%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26generic%3Dfalse%26interface%3Dorg.apache.dubbo.demo.DemoService%26logger%3Dlog4j%26methods%3DsayHello%26pid%3D1072%26release%3D2.7.0%26side%3Dprovider%26timestamp%3D1596076187605&logger=log4j&pid=1072&release=2.7.0&timestamp=1596076187072
    

    ②、获取providerUrl 服务提供者url

    dubbo://192.168.7.81:20881/org.apache.dubbo.demo.DemoService?anyhost=true&application=dubbo-demo-provider1-application&bean.name=ServiceBean:org.apache.dubbo.demo.DemoService&bind.ip=192.168.7.81&bind.port=20881&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&logger=log4j&methods=sayHello&pid=1072&release=2.7.0&side=provider&timestamp=1596076187605
    

    ③、生成overrideSubscribeUrl,与监听有关
    在服务提供者url的基础上,生成一个overrideSubscribeUrl,协议为provider://,增加参数category=configurators&check=false
    overrideSubscribeUrl是用来对动态配置监听的,需要监听的服务和监听的类型(configurators, 老版本)
    一个overrideSubscribeUrl对应一个OverrideListener,用来监听overrideSubscribeUrl变化事件

    provider://192.168.7.81:20881/org.apache.dubbo.demo.DemoService?anyhost=true&application=dubbo-demo-provider1-application&bean.name=ServiceBean:org.apache.dubbo.demo.DemoService&bind.ip=192.168.7.81&bind.port=20881&category=configurators&check=false&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&logger=log4j&methods=sayHello&pid=1072&release=2.7.0&side=provider&timestamp=1596076187605
    

    ④、doLocalExport导出
    此时服务协议是dubbo,DubboProtocol被ProtocolFilterWrapper包裹,ProtocolFilterWrapper被ProtocolListenerWrapper包裹


    image.png

    DubboProtocol

    1、export
    org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper#export
    返回结果被ListenerExporterWrapper包裹


    image.png

    2、export
    org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper#export


    image.png
    ①、buildInvokerChain
    org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper#buildInvokerChain
    根据url获取filter,根据url中的parameters匹配key所对应的filter,也会匹配group
    image.png
    image.png
    image.png

    EchoFilter、ClassLoaderFilter、GenericFilter、ContextFilter、TraceFilter、TimeoutFilter、MonitorFilter、ExceptionFilter
    返回包裹了Filter的CallbackRegistrationInvoker
    3、export
    org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#export


    image.png
    获取url、获取key、isStubSupportEvent=false、isCallbackservice=false
    image.png
    开启Server。dubbo协议是NettyServer。dubbo协议的mina,netty,http协议的jetty,servlet等,默认为netty
    org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#createServer
    其中创建Server,最重要的是通过url绑定端口,和对应的请求处理器。requestHandler是请求处理器,类型为ExchangeHandler。表示从url的端口接收到请求后,requestHandler来进行处理
    image.png
    4、register
    org.apache.dubbo.registry.integration.RegistryProtocol#export
    在调用doLocalExport方法进入DubboProtocol协议开启Server之后,便会调用RegistryProtocol的register注册到注册中心zookeeper中
    image.png
    registry表示注册中心,registeredProviderUrl表示存入到注册中心去的providerUrl,会对其中的参数进行简化
    providerInvokerWrapper表示服务提供者Invoker、该服务对应的注册中心地址、简化后的服务registeredProviderUrl的包装类
    ①、register
    org.apache.dubbo.registry.integration.RegistryProtocol#register
    image.png

    ②、register
    org.apache.dubbo.registry.support.FailbackRegistry#register


    image.png
    ③、doRegister
    调用zkClient.create,注册到zookeeper中
    image.png
    image.png

    动态配置监听

    在服务导出过程中,需要对动态配置中心的数据进行监听。如果发生更改,可以及时做出反映。
    这里用到了Zookeeper的Watcher机制。
    1、配置中心的路径与动态配置路径是不相同的,这里需要区分开来
    配置中心的路径是:
    ①、应用:/dubbo/config/dubbo/org.apache.dubbo.demo.DemoService/dubbo.properties节点的内容
    ②、全局:/dubbo/config/dubbo/dubbo.properties节点的内容
    2、对于动态配置的监听有版本的差别
    在2.7之前,只可以对单个服务进行监听,不可以对应用监听
    /dubbo/org.apache.dubbo.demo.DemoService/configurators/* 只对路径名字监听,不监听内容
    在2.7之后,服务和应用都可以监听
    服务: /dubbo/config/dubbo/org.apache.dubbo.demo.DemoService.configurators 节点的内容
    应用: /dubbo/config/dubbo/dubbo-demo-provider-application.configurators 节点的内容
    3、监听时机RegistryProtocol#export
    org.apache.dubbo.registry.integration.RegistryProtocol#export


    image.png
    2.6之后版本监听器原理

    0、overrideUrlWithConfig
    org.apache.dubbo.registry.integration.RegistryProtocol#overrideUrlWithConfig


    image.png

    providerConfigurationListener是RegistryProtocol的一个属性值,在创建RegistryProtocol类时,便会得到这个应用配置的监听器


    image.png
    1、ProviderConfigurationListener 应用监听器
    应用配置,providerConfigurationListener是在属性那里直接初始化好的,providerConfigurationListener会监听配置中心的应用配置信息变动
    org.apache.dubbo.registry.integration.RegistryProtocol.ProviderConfigurationListener#ProviderConfigurationListener
    image.png

    org.apache.dubbo.registry.integration.AbstractConfiguratorListener#initWith
    ①、获取dynamicConfiguration


    image.png
    ②、指定路径添加监听器addListener
    org.apache.dubbo.configcenter.DynamicConfiguration#addListener
    image.png
    org.apache.dubbo.configcenter.support.zookeeper.ZookeeperDynamicConfiguration#addListener
    image.png
    ③、获取路径getPathKey
    org.apache.dubbo.configcenter.support.zookeeper.ZookeeperDynamicConfiguration#getPathKey
    image.png
    所以,key值是dubbo-demo-provider1-application.configurators的监听路径是
    /dubbo/config/dubbo/dubbo-demo-provider1-application.configurators

    rawConfig表示从配置中心获取当前应用的动态配置数据,如果存在应用配置信息则根据配置信息生成Configurator
    ④、genConfiguratorsFromRawRule
    org.apache.dubbo.registry.integration.AbstractConfiguratorListener#genConfiguratorsFromRawRule
    先把应用或服务配置转成url,再根据url生成对应的Configurator


    image.png
    2、ServiceConfigurationListener 服务监听器
    ServiceConfigurationListener会监听配置中心的服务信息配置信息变动,每注册一个服务都会生成一个服务监听器
    image.png
    org.apache.dubbo.registry.integration.RegistryProtocol.ServiceConfigurationListener#ServiceConfigurationListener
    image.png
    org.apache.dubbo.configcenter.support.zookeeper.ZookeeperDynamicConfiguration#getPathKey
    image.png
    key是org.apache.dubbo.demo.DemoService::.configurators,得到的监听路径是/dubbo/config/dubbo/org.apache.dubbo.demo.DemoService::.configurators
    3、把服务监听添加到serviceConfigurationListeners集合中
    image.png
    2.6以及之前版本监听器原理
    image.png

    org.apache.dubbo.registry.support.FailbackRegistry#subscribe


    image.png

    org.apache.dubbo.registry.zookeeper.ZookeeperRegistry#doSubscribe
    进行订阅,先看父类的subscribe方法。订阅所有服务


    image.png
    image.png
    单独订阅某一个服务,根据监听地址去拿listeners,如果没有则生成
    image.png

    添加跟zookeeper相关的ChildListener


    image.png
    这里的urls就是从现在所引入的服务的目录下查到的url,比如下面这个三个目录下的路径(这里会在服务引入时,有这些值)
    /dubbo/org.apache.dubbo.demo.DemoService/providers
    /dubbo/org.apache.dubbo.demo.DemoService/configurators
    /dubbo/org.apache.dubbo.demo.DemoService/routers
    OverrideListener触发

    OverrideListener实现了NotifyListener,OverrideListener订阅的subscribeUrl发生改变OverrideListener将会接收到通知
    1、notify
    org.apache.dubbo.registry.integration.RegistryProtocol.OverrideListener#notify
    对发生了变化的url进行过滤,只获取url是override协议或参数category=onfigurators的url


    image.png

    根据Override协议修改
    2、doOverrideIfNecessary
    org.apache.dubbo.registry.integration.RegistryProtocol.OverrideListener#doOverrideIfNecessary
    根据configurators修改url


    image.png
    修改过的newUrl和目前的currentUrl不相同,则重新按newUrl导出
    image.png
    3、reExport
    org.apache.dubbo.registry.integration.RegistryProtocol#reExport
    image.png

    根据newInvokerUrl获取exporter进行导出、得到最新的注册registryUrl。如果新的服务url和这个服务之前的服务url不相等,则需要把新的服务url注册到注册中心。
    4、process
    ProviderConfigurationListener和ServiceConfigurationListener都实现了AbstractConfiguratorListener,所以如果配置发生了改变将会触发org.apache.dubbo.registry.integration.AbstractConfiguratorListener#process方法


    image.png
    org.apache.dubbo.registry.integration.RegistryProtocol.OverrideListener#doOverrideIfNecessary
    会调用子类doOverrideIfNecessary方法

    Exporter结构

    org.apache.dubbo.registry.integration.RegistryProtocol#doLocalExport调用之后得到的exporter从外到内依次是
    RegistryProtocol$ExporterChangeableWrapper、ListenerExporterWrapper、DubboExporter
    在org.apache.dubbo.registry.integration.RegistryProtocol#export返回结果又被DestroyableExporter包裹。


    image.png

    1、DestroyableExporter
    org.apache.dubbo.registry.integration.RegistryProtocol.DestroyableExporter#unexport


    image.png
    2、ExporterChangeableWrapper
    org.apache.dubbo.registry.integration.RegistryProtocol.ExporterChangeableWrapper#unexport
    从注册中心删除服务URL、解绑当前服务的监听器Listener
    image.png
    image.png

    3、ListenerExporterWrapper
    org.apache.dubbo.rpc.listener.ListenerExporterWrapper#unexport
    在unexport对应服务之后,把服务监听器移除


    image.png
    4、AbstractExporter
    org.apache.dubbo.rpc.protocol.AbstractExporter#unexport
    image.png
    这几个Exporter主要在于getInvoker和unexport方法

    总结:

    dubbo服务导出的核心就是根据各种位置的配置构建服务url,并注册到注册中心。
    还有一点是服务导出生成的Export结构是为了服务消费端进行调用的。
    其中,开启服务也是为了与服务消费端进行调用信息的传输。

    相关文章

      网友评论

        本文标题:Dubbo之服务导出源码分析

        本文链接:https://www.haomeiwen.com/subject/pbtzlktx.html