前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[dubbo 源码之 ]1. 服务提供方如何发布服务

[dubbo 源码之 ]1. 服务提供方如何发布服务

作者头像
Isaac Zhang
发布2020-03-19 14:57:52
4420
发布2020-03-19 14:57:52
举报
文章被收录于专栏:奔跑的人生奔跑的人生

服务发布

启动流程
1.ServiceConfig#export

服务提供方在启动部署时,dubbo会调用ServiceConfig#export来激活服务发布流程,如下所示:

  • Java API:
  • XML

查看export源码可知,总共有三种服务导出选项: java public synchronized void export() { //1. 是否导出 if (!shouldExport()) { return; } ... //2.延迟导出 if (shouldDelay()) { DELAY_EXPORT_EXECUTOR.schedule(this::doExport, getDelay(), TimeUnit.MILLISECONDS); } else { //3.立刻导出 doExport(); } }

2.ServiceConfig#doExport

此方法主要是根据设置的属性进行合法性检查,主要包含是否已被导出,doExportUrls();

3.doExportUrls
4.ConfigValidationUtils#loadRegistries

此方法用来加载所有的服务注册中心对象,在dubbo中,一个service可以被注册到多个注册中心。 通过doExportUrlsFor1Protocol(protocolConfig, registryURLs);

5.doExportUrlsFor1Protocol

在此方法中会将所有的参数封装成org.apache.dubbo.common.URL对象,然后执行具体的服务导出。

具体过程分为:

  • 1.解析MethodConfig配置(单独的方法调用参数设置)
  • 2.泛型调用类型设置
  • 3.拼接URL参数
  • 4.导出具体服务 导出又分为四种范围(scope):
    • SCOPE_NONE = "none",如果设定为none,表示该服务不导出。
    • SCOPE_LOCAL = "local" ,如果设定为local,表示该服务导出到本地(injvm--伪协议,实现类为:org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol
      • SCOPE_REMOTE = "remote",如果设定为remote,表示该服务导出到远程。
    • 如果有注册中心,发布到注册中心
    • 如果没有注册中心,则表示服务是直连方式
    • dubbo-2.7.0开始,新增加了WritableMetadataService 来存储dubbo 服务的元数据,元数据可以存储在远端配置中心和本地,默认是存储在本地,通过设置:METADATA_KEY = "metadata"
      • DEFAULT_METADATA_STORAGE_TYPE = "local"
      • REMOTE_METADATA_STORAGE_TYPE = "remote" java /** * @since 2.7.0 * ServiceData Store */ WritableMetadataService metadataService = WritableMetadataService.getExtension(url.getParameter(METADATA_KEY, DEFAULT_METADATA_STORAGE_TYPE)); if (metadataService != null) { metadataService.publishServiceDefinition(url); }
      • 不设置,导出到本地和远端
    • 最终执行导出的代码如下

由于protocolPROXY_FACTORY都是扩展适配类,跟踪代码我们可以发现:

  • 执行PROXY_FACTORY.getInvoker的时候实际上首先执行扩展接口ProxyFactory的适配类ProxyFactory$AdaptivegetInvoker方法,根据URL中参数proxy的设置类型选择具体的代理工厂,默认使用的是javassist,,因此又调用了org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory#getInvoker来获取代理实现类,代码如下:

上面代码有2个目的:

  1. inal Wrapper wrapper = Wrapper.getWrapper(...);用来生成具体serviceImpl的包装类,减少反射的性能损耗;
  2. return new AbstractProxyInvoker<T>... 返回了一个抽象的代理invoker,并且重写了doInvoker方法,重写之后使用包装类中的invokeMethod来调用方法。

经过上述2步,服务提供方就将具体的实现类转换为Invoker代理。

  • 然后,当执行protocol.export(),实际上也是调用了Protocol$Adaptive#export()方法,同时也分为两种情况
    • 如果为远程暴露,则执行RegistryProtocol#export
    • 如果为本地暴露,则只需InjvmProtocol#export

    由于dubbo的增强SPI特性支持,injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));,则在调用之前会一层一层调用,ProtocolFilterWrapper->ProtocolListenerWrapper->QosProtocolWrapper,最后会调用export方法,此方法会将Invoker转换为Exporter对象,在org.apache.dubbo.registry.integration.RegistryProtocol#export方法中,org.apache.dubbo.registry.integration.RegistryProtocol#doLocalExport方法启NettyServer来监听服务,org.apache.dubbo.registry.integration.RegistryProtocol#register将当前的服务注册到注册中心。

    • doLocalExport 是如何启动NettyServer呢?

可以看到代码执行到openServer,因为key=getAddress()=ip+port,因此,同一台机器只会开启一个NettyServer.

对于org.apache.dubbo.remoting.Transporter 的适配类选择有三种:MinaTransporter、 NettyTransporter、GrizzlyTransporter,关于JavaNIO:Apache Mina、JBoss Netty、Sun Grizzly 框架对比:传送门

  • NettyServer启动之后,回到org.apache.dubbo.registry.integration.RegistryProtocol#export方法,继续执行将服务注册到注册中心,我们以Zookeeper为例:
    • 1.首先查找所有注册中心 final Registry registry = getRegistry(originInvoker); ... protected Registry getRegistry(final Invoker<?> originInvoker) { URL registryUrl = getRegistryUrl(originInvoker); return registryFactory.getRegistry(registryUrl); } 因为RegistryFactory是一个SPI扩展接口,代码中设置的为zookeeper,因此这里调用的是ZookeeperRegistryFactory,继承自:org.apache.dubbo.registry.support.AbstractRegistryFactory#getRegistry(org.apache.dubbo.common.URL),在此方法中调用了createRegistry,但是ZookeeperRegistryFactory重写了createRegistry,因此具体调用的是ZookeeperRegistryFactory#createRegistry,该方法返回了一个new ZookeeperRegistry(url, zookeeperTransporter)实例对象。
    • 2.开始注册,RegistryProtocol#register方法执行注册动作,首先获取到我们在上一步找到的注册中心ZookeeperRegistry,ZookeeperRegistry 执行父类org.apache.dubbo.registry.support.FailbackRegistry#register,在该方法中会调用抽象方法:doRegister,ZookeeperRegistry 重写了改方法,则执行ZookeeperRegistry#doRegister ,如下: @Override public void doRegister(URL url) { try { zkClient.create(toUrlPath(url), url.getParameter(DYNAMIC_KEY, true)); } catch (Throwable e) { throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e); } }
    • 3.toUrlPath方法会把org.apache.dubbo.common.URL转换格式后存储到zookeeper,如下:

至此,服务消费端就可以从注册中心获取服务提供service进行调用了,下节我们继续来分析,消费端是如何从注册中心拉取service进行处理的。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-02-28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 服务发布
    • 启动流程
      • 1.ServiceConfig#export
      • 2.ServiceConfig#doExport
      • 3.doExportUrls
      • 4.ConfigValidationUtils#loadRegistries
      • 5.doExportUrlsFor1Protocol
相关产品与服务
微服务引擎 TSE
微服务引擎(Tencent Cloud Service Engine)提供开箱即用的云上全场景微服务解决方案。支持开源增强的云原生注册配置中心(Zookeeper、Nacos 和 Apollo),北极星网格(腾讯自研并开源的 PolarisMesh)、云原生 API 网关(Kong)以及微服务应用托管的弹性微服务平台。微服务引擎完全兼容开源版本的使用方式,在功能、可用性和可运维性等多个方面进行增强。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档