Dubbo概述--启动过程

Dubbo–启动过程

写在前面

本文参考了Dubbo官方手册结合Dubbo2.6.1版本源码分析。推荐先阅读官方手册

鉴于个人水平有限,如有不正确的地方请指出,欢迎一起讨论,谢谢!

启动过程

启动过程主要从Provider和Consumer进行分析。每个Provider最终会实例化为一个ServiceBean的实例,而每个Consumer通过实现自FactoryBean接口的ReferenceBean在首次调用时创建代理实例(也可以通过init属性设置非延迟加载)。

Provier启动过程(暴露服务)

Provider的启动过程默认由afterProperties方法触发,也可以通过Spring的刷新事件触发或者定时触发(通过delay属性控制),不需要通过代码getBean即可完成Provider的启动。

整个启动过程围绕两个URL,一个是调用服务的URL,另一个是同Registry通信的URL。在整个启动过程中通过向URL添加、读取属性(主要是Protocol)、参数,来串联起整个过程中的扩展(Trasport/Protocol等)的指定和启动的处理逻辑。

完成启动步骤(ServiceConfig.doExport()方法)概述如下:

  1. 检查并设置exported属性

  2. 检查默认配置,即检查provider属性是否为空,为空则实例化一个。

  3. 依照provider->module->application的顺序设置自身为空的属性(说明自身设置优先级高,且配置优先级privider>module>application)。

  4. 检查Provider提供服务的接口是否有服务方法以及接口实现类是否实现自接口。

  5. 检查application、registry、protocol配置,如果对应对象不存在则进行处理。

  6. 对本对象进行属性设置,属性值来源于-D或者properties配置文件,优先-D。

  7. 检查stub、local、mock配置,类是非存在、配饰是否合法、执行的构造器是否存在等。

    • stub,在客户端执行,用于客户端调用服务端时进行调用预处理或异常处理。相当于服务端对客户端的要求,客户端在调用时使用的是stub类。
    • local,已废弃,被stub取代。
    • mock,在客户端执行,专门用于调用服务端发生异常时进行异常处理。
  8. 设置服务类的路径

  9. 基于各个Registry的配置,构造各个Registry的访问URL

    • 将application、registry中带有Parameter注解方法的key、value作为参数添加到URL中。
    • 将application、registry中getParameters方法返回的Map中的key、value作为参数添加到URL中。
    • 将path(访问路径)、dubbo(dubbo版本)、timestamp(URL构建时间)添加到URL中。
    • URL基本的protocol:IP:port三个部分优先使用registry的值,没有则使用默认的:dubbo和9090,IP部分必须指定。
    • 设置URL的protocol部分为registry,将实际的protocol以name为registry,value为实际protocol值的方式添加到URL参数部分。
  10. 根据配置构造服务Bean自身被调用时的访问URL

    • 添加固定参数:side、dubbo、timestamp、pid
    • 将application、module、provider、protocolConfig以及自身中带有Parameter注解方法的key、value作为参数添加到URL中。
    • 将application、module、provider、protocolConfig中getParameters方法返回的Map中的key、value作为参数添加到URL中。
    • 如果Provider内部有Method配置,则根据method配置添加带有Parameter注解方法和getParameters方法返回的Map的key、value到URL参数中。
    • 尝试添加可能存在的固定参数:generic、revision、token
    • 从Provider的接口中获取所有的方法,以逗号分隔的方式添加到名为methods的参数上。此处的参数名为methods而根据Method配置添加的相关URL参数并不是此参数名且接口中的方法参数不会体现在URL参数列表中
  11. 根据scope属性的配置决定代表Provider的URL注册到Registry还是Local或者两者都注册或都不注册。

  12. 如果需要将服务导出为本地,则进行如下处理:

    • 修改Provider的调用URL,修改protocol为injvm、host为127.0.0.1、port为0
    • 将Provider实际提供类保存到ThreadLocal中
    • 使用JavassistProxyFactory通过Wrapper类动态生成Wrapper类的子类,作为AbstractProxyInvoker类doInvoke方法的实际处理类
    • 由于之前已经将protocol修改为injvm,所以通过InjvmProtocol的export方法导出,生成InjvmExporter
    • 将导出的InjvmExporter添加到ServiceConfig.exporters集合中
  13. 如果需要将服务导出到注册中心,则进行如下处理:

    • 根据配置向Provider调用URL中添加dynamic以及monitor相关参数值

    • 使用JavassistProxyFactory通过Wrapper类动态生成Wrapper类的子类,作为AbstractProxyInvoker类doInvoke方法的实际处理类。此Invoker和本地导出的Invoker是相同的的类

    • 将上一步返回的Invoker和服务配置包装为DelegateProviderMetaDataInvoker类

    • 由于之前JavassistProxyFactory返回的AbstractProxyInvoker中,URL的Protocol为Registry,所以使用RegistryProtocol的export方法导出,生成DestroyableExporter

    • RegistryProtocol首先根据服务调用URL调用其对应的Protocol的export打开本地服务,服务处理类根据不同的Protocol包装为不同的类,但都最终会调用到之前的Invoker类

    Provider Protocol 服务 服务处理类
    dubbo netty(grizzly/mima/netty4) – Transport服务扩展 DubboProtocol.ExchangeHandlerAdapter
    RMI Spring内嵌的RmiServiceExporter 直接使用Invoker类
    hessian jetty(Servlet/Tomcat) – HttpBinder服务扩展 HessianProtocol.HessianHandler
    injvm JVM内部调用
    • RegistryProtocol内部处理ProviderURL和RegistryURL,删除不必要的参数等

    • 通过RegistryProtocol内部注入的RegistryFactory(ExtensionLoader注入实现)获得Registry对象,进而向Registry注册ProviderURL

    Registry Protocol Registry Description
    dubbo Simple Registry Registry本身是一个RPC服务者,通过文件保存Provider信息
    multicast 通过使用JDK自带的广播功能实现自动发现
    redis Redis 通过Redis自身的可靠性保证
    zookeeper Zookeeper 通过Zookeeper自身的可靠性保证
    mockregistry 只是用于测试打桩
    • 使用ProviderConsumerRegTable缓存Provider信息并设置为已经注册

    • 向注册中心订阅注册一个监控服务配置改变的监听器OverrideListener。

Consumer启动过程(引用服务)

Consumer启动实际上是ReferenceBean中getObject获取代理类的过程。ReferenceConfig.init()方法

  1. 检查Consumer默认配置,没有则初始化一个并对属性赋值。
  2. 加载服务接口类,并检查接口类和其内部方法
  3. 优先尝试从userHome目录下的dubbo-resolve.properties文件中根据接口名获取其调用URL
  4. 依照consumer->module->application的顺序设置自身为空的属性(说明自身设置优先级高,且配置优先级consumer>module>application)。
  5. 检查application配置
  6. 检查stub、local、mock配置,类是非存在、配饰是否合法、执行的构造器是否存在等。
    • stub,在客户端执行,用于客户端调用服务端时进行调用预处理或异常处理。相当于服务端对客户端的要求,客户端在调用时使用的是stub类。
    • local,已废弃,被stub取代。
    • mock,在客户端执行,专门用于调用服务端发生异常时进行异常处理。
  7. 将application、consumer、module以及side、dubbo版本等信息存放到map中
  8. 首先判断是否从JVM本地调用服务,如果是本地,则直接生成本地调用URL以及根据URL生成本地调用Invoker(InjvmInvoker)
  9. 如果不是本地调用,则判断之前从dubbo-resolve.properties文件中是否根据接口名加载到了服务URL,如果有则直接到第11步
  10. 如果没有从文件中加载到了服务URL,则加载所有的Registry配置获取所有的Registry访问URL
  11. 根据解析出的URL实例化Invoker
    • 如果只有一个URL则直接根据URL获取Protocol,进而向Registry发布自身相关信息(Consumer、Router),以及订阅Provider、Configuration、Router信息。最终获取Invoker(此Invoker内包含Cluster处理方式以及Directory)
    • 如果有多个URL则逐个按照一个URL的方式处理,然后将多个Invoker通过StaticDirectory组织后由Cluster组合为一个Invoker
  12. 将Cluster组织好的Invoker通过ProxyFactory动态生成Consumer端的代理类,供Consumer调用。这个通过Javassist生成的动态代理类一般情况下会实现EchoService和服务类接口

猜你喜欢

转载自blog.csdn.net/woshismyawei/article/details/80076946