dubbo源码—service export

在应用编写好服务并进行以后,dubbo负责将服务export出去,dubbo export服务的时候主要作了如下几件事:java

  • 将服务export到本地(根据scope的配置)
  • 建立Invoker(启动本地NettyServer,监听指定端口,等待请求)
  • 注册provider的信息到registry,供consumer发现并订阅服务
  • 订阅registry中的configurator节点,能够动态更改部分provider的配置

暴露服务的配置方式有:spring

  • 直接经过API方式
  • 经过xml配置
  • 经过注解

ServiceBean加载和初始化

以经常使用的xml配置为例,前面说了dubbo的xml自定义标签最后都是将对应的bean注入容器中,<dubbo:service /> 对应的就是ServiceBean,service暴露服务就在spring初始化ServiceBean的时候网络

<dubbo:service interface="com.test.service.TestDubboService" ref="testDubboServiceImpl"/>

dubbo解析xml会将对应的bean—ServiceBean注入到spring容器中,因为解析xml的时候配置的bean是非lazyInit的,因此在spring容器初始化完成以后,会初始化全部非lazyInit的bean。app

在spring容器初始化后,会广播ContextRefreshedEvent事件通知,ServiceBean实现了ApplicationListener,在收到该事件以后调用export方法框架

// AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
  // Instantiate all remaining (non-lazy-init) singletons.
  finishBeanFactoryInitialization(beanFactory);
  
  // Last step: publish corresponding event.
  // 里面会广播ContextRefreshedEvent事件
  finishRefresh();
}

// ServiceBean
public void onApplicationEvent(ApplicationEvent event) {
  // 在容器初始化完成以后收到ContextRefreshedEvent事件,开始export服务
  if (ContextRefreshedEvent.class.getName().equals(event.getClass().getName())) {
    if (isDelay() && ! isExported() && ! isUnexported()) {
      if (logger.isInfoEnabled()) {
        logger.info("The service ready on spring started. service: " + getInterface());
      }
      export();
    }
  }
}

服务export从ServiceConfig#export开始jvm

  1. export:判断是不是延迟启动,若是是延迟启动则启动守护线程,sleep指定时间以后再调用doExport,不然直接调用
  2. doExport:主要工做是检查并配置
    1. 初始化application、registries、monitor等配置
    2. 判断是不是泛化调用,若是不是,判断interface和ref是否合法
    3. 检查并配置application、registries、protocols、ServiceConfig自己,找对应配置类属性的set方法,依次从System.getProperty(-D参数指定,或者set进去的配置)、dubbo.properties.file参数执行的配置文件文件中查找对应的属性,而后调用set 方法配置
    4. 检查是否有stub和mock配置,若是有配置,判断配置是否合法。若是有stub配置:判断stub类是否有该服务interface类型的构造方法;若是有mock配置:若是直接是"return"表达式,parse返回的value是否合法,不然须要判断mockClass是否有无参的构造方法
  3. loadRegistries:加载全部的registries,可能会有多个注册中心,查找全部的registries配置并返回符合条件的
    1. 针对每个registry配置,从applicationConfig、registryConfig获取参数拼装registryUrl
    2. 条件是:若是是provider则register不能配置为false(能够不配置,若是配置了必须为true);若是不是provider,subscribe不能配置为false(能够不配置,若是配置了必须为true)。
  4. doExportUrls:因为dubbo支持多个协议,因此dubbo针对每一种协议都会在每个注册中心注册一遍
  5. doExportUrlsFor1Protocol:根据配置来拼装URL,在export的整个过程当中靠URL来传递配置
    1. 获取配置的协议名称,若是没有配置协议名称,则使用默认协议:dubbo
    2. 获取配置的ip:port,若是port没有配置从默认端口20880开始依次向后寻找可用的port,若是port配置为-1表示随机选取一个port
    3. 从application、module、provider、ptotocol等获取配置,将这些配置加入到map中未来用来生成URL
    4. 判断是否有dubbo:argument配置,将对应的配置也加入map
    5. 是不是泛化(Generic)调用,若是没有则判断是否有method级的配置
    6. 是不是injvm的调用,若是是,则不须要注册到注册中心
    7. 根据前面host:port、protocolName、map构造URL
    8. 判断scope的配置,为none表示不暴露服务,配置为remote则export到local和remote,若是配置为local则只export到local

export服务到本地

若是scope没有配置或者配置local、remote,dubbo会将服务export到本地,意思就是:将服务以injvm协议export出去,若是是同一个jvm的应用能够直接经过jvm发起调用,而不须要经过网络发起远程调用。ide

export到本地主要作了如下几件事:ui

  1. 将url的协议配置为jvm,host:port配置为127.0.0.1:0
  2. 构造filter链,虽然是本地export,可是会通过定义好的filter
  3. 构造InjvmExporter

建立Invoker

若是scope没有配置或者配置remote,dubbo会建立invoker,建立invoker的时候会启动NettyServer,监听指定的端口等待consumer请求。在dubbo中provider和consumer端都会有Invoker,实现的是同一个接口,可是不一样的实现,invoker的意义就是服务的代理,provider侧的invoker就是提供服务的可执行体,在netty接收到请求以后会经过invoker来处理,最后调用目标服务。url

建立invoker并启动NettyServer的调用堆栈线程

export的主要过程是:

  1. 建立Invoker,proxyFactory.getInvoker
  2. 建立filter链,ProtocolFilterWrapper#buildInvokerChain
  3. 调用配置的exporter的listener,ListenerExporterWrapper#ListenerExporterWrapper
  4. 启动NettyServer,DubboProtocol#openServer

filter和listener是可扩展的,能够本身实现filter和listener,按照SPI方式配置好,dubbo会自动加载。

注册到注册中心并订阅

前面只是完成service的启动并具有可被请求的状态,可是dubbo做为一个支持服务自发现的框架,还会把provider的信息注册到registry,而且订阅configurators。

注册的调用堆栈是

注册和订阅主要逻辑在RegistryProtocol#export

  1. 启动NettyServer
  2. 注册providerUrl
  3. 订阅configurators

registry就是一个目录服务,注册的过程也就是建立对应的目录,并订阅关心的目录变化。provider会在registry中建立相似以下的目录结构

其中provider注册的url为,会建立com.foo.BarService、provider和providerUrl节点

dubbo/com.test.service.TestDubboService/providers/dubbo%3A%2F%2F192.168.0.102%3A20880%2Fcom.test.service.TestDubboService%3Fapplication%3Dcom.test.demo%26default.export%3Dtrue%26export%3Dtrue%26generic%3Dfalse%26interface%3Dcom.test.service.TestDubboService%26pid%3D45599%26side%3Dprovider%26timestamp%3D1515313385792

接下来会建立并订阅configurators节点,订阅的意思就是监听configurators及其子节点,建立configurators的时候会添加listener,provider端监听configurators的listener是:

com.alibaba.dubbo.registry.integration.RegistryProtocol.OverrideListener#notify

在治理中心中修改provider的配置的时候,注册中心会通知监听的listener,provider会进行相关配置。

总结

export服务是dubbo关键路径中的第一步,此时dubbo已经具有了被consumer自动发现并调用的条件,接下来就是consumer发现服务。

相关文章
相关标签/搜索