今天我们要分析的就是Dubbo的服务暴露过程,这个过程属于Dubbo的核心过程之一了,因为Dubbo的大体流程就是服务暴露->服务引用->服务消费这几个主流程,当然还会涉及到注册发现、负载均衡、集群容错等,我们会从源码的角度来给大家分析这个服务暴露的流程,当然大家也不用发愁,我们不会把代码分析的那么细,咱也没那个时间和精力,所以大家不用担心读不懂,我也会和大家说一下总结性话术来帮助大家去理解

Dubbo的三种调用方式:

1、注解@Reference调用(这是最常用的)

@Reference(version = "1.0.0")
private UserService userService;

2、指定dubbo的服务端口进行调用

String url = "dubbo://192.168.1.102:10086/ccom.dayu.api.business.cache.IMerchantRedisCache?version=1.0.0";//更改不同的Dubbo服务暴露的ip地址&端口          ReferenceBean<IMerchantRedisCache> referenceBean = new ReferenceBean<IMerchantRedisCache>();  referenceBean.setApplicationContext(applicationContext);  referenceBean.setInterface(IMerchantRedisCache.class);  referenceBean.setUrl(url);  try {  referenceBean.afterPropertiesSet();  IMerchantRedisCache merchantRedisCache = referenceBean.get();PlaneResDto<MerchantItem> resDto = merchantRedisCache.getInDubbo(419248146L);JsonPrinter.printJson(resDto);Assert.assertTrue(SysCode.SUCCESS.equals(resDto.getRspCd()));  } catch (Exception e) {  e.printStackTrace();  }

3、从Zookeeper中获取到服务提供者的信息,再进行调用

ZkClient zkClient = new ZkClient(ZKServers,10000,10000,new SerializableSerializer());
List<String> lists = zkClient.getChildren("/dubbo/com.yc.api.business.cache.ICacheFacade/providers");

URL

URL统一模型的意义

在不谈及 dubbo 时,我们中的大多数人对 URL 这个概念并不会感到陌生。统一资源定位器 (Uniform Resource Locators)应该是最广为人知的一个 RFC 规范,它的定义也非常简单,因特网上的可用资源可以用简单字符串来表示,该文档就是描述了这种字符串的语法和语义,而这些字符串则被称为:“统一资源定位器”(URL)

一个标准的 URL 格式至多可以包含如下的几个部分

protocol://username:password@host:port/path?key=value&key=value

接下来我们看下Dubbo中的URL:

public URL(String protocol,String username,String password,String host,int port,String path,Map<String, String> parameters) {if (StringUtils.isEmpty(username)&& StringUtils.isNotEmpty(password)) {throw new IllegalArgumentException("Invalid url, password without username!");}this.urlAddress = new PathURLAddress(protocol, username, password, path, host, port);this.urlParam = URLParam.parse(parameters);}

  protocol:一般是 dubbo 中的各种协议 如:dubbo、thrift、http、zk

  username/password:用户名/密码

  host/port:主机IP地址/端口号

  path:接口名称

  parameter:参数键值对

对于 dubbo 中的 URL,有人理解为配置总线,有人理解为统一配置模型,说法虽然不同,但都是在表达一个意思,这样的 URL 在 dubbo 中被当做是公共契约,所有扩展点参数都包含 URL 参数,URL 作为上下文信息贯穿整个扩展点设计体系。

在没有 URL 之前,只能以字符串传递参数,不停的解析和拼装,导致相同类型的接口,参数时而 Map, 时而 Parameters 类包装:

export(String url) createExporter(String host, int port, Parameters params)

使用 URL一致性模型:

export(URL url) createExporter(URL url)

在最新的 dubbo 代码中,我们可以看到大量使用 URL 来进行上下文之间信息的传递,这样的好处是显而易见的:

1.   编码规范,使得代码易写,易读

2.   可扩展性强,URL 相当于参数的集合(相当于一个 Map)

3.   统一模型,各个扩展模块都可以使用它作为参数的表达形式

服务暴露主流程

服务暴露主流程,大致可以分为两个角度进行分析流程,大家先简单理解下,下面我带大家一步步的看源码:

客观流程角度:

前置工作,主要用于检查参数,组装 URL。

导出服务,包含暴露服务到本地 (JVM),和暴露服务到远程两个过程。

向注册中心注册服务,用于服务发现。

对象转换角度:

首先将服务的实现封装成一个Invoker,Invoker中封装了服务的实现类。

将Invoker封装成Exporter,并缓存起来,缓存里使用Invoker的url作为key。

服务端Server启动,监听端口。

初始化,这属于入口,我们来看下其中的ServiceBean这个类的使用,这里说一个小插曲,经过对比发现最新的继承的是ApplicationEventPublisherAware接口,而旧版本的继承的是ApplicationListener<ContextRefreshedEvent>接口

哦对了,源码地址在:https://gitee.com/dayumm

大部分博客视频讲解服务暴露的export方法根源是ServiceConfig的export方法,ServiceBean继承了ServiceConfig,利用实现ApplicationListener<ContextRefreshedEvent>接口的onApplicationEvent方法最终调用ServiceConfig的export方法

然而最新版本实现的ApplicationEventPublisherAware并没有去调用ServiceConfig的export方法,只是ServiceBean在完成export的时候利用这个接口去发布一个exported的事件,也就是暴露后的事件,并不是暴露事件

所以新继承的ApplicationEventPublisherAware这个接口好像并没有直接对服务暴露过程有作用。那么ServiceConfig的export的方法到底再哪里才会进行调用呢?

追根溯源发现DubboBootstrapApplicationListener这个类,继承了ApplicationListener和ApplicationContextAware,并最后调用到DubboBootStrap方法

发现它再start方法中有一行exportServices,顾名思义是导出服务或者暴露服务,点进去看exportServices

这个exportServices会最中调用ServiceConfigBase的export方法,我们看下这个ServiceConfigBase是何方神圣呢

打开ServiceConfig的结构图看下:

原来如此,原来是父类,这是一个抽象方法,最终调用的就是ServiceConfig中的export方法了,我们重点要看的是export中的doExport方法

可以看到 Dubbo 支持多注册中心,并且支持多个协议,一个服务如果有多个协议那么就都需要暴露,比如同时支持 dubbo 协议和 hessian 协议,那么需要将这个服务用两种协议分别向多个注册中心(如果有多个的话)暴露注册。

我们点进来doExportUrlsFor1Protocol这个方法看,这个方法很长,我们就不一步步的去看了,滑到方法最后这里:

本地暴露和远程暴露

继续看源码,快结束了,冲

本地暴露:调用的服务在同一台JVM的时候会直接本地调用

Protocol 的 export 方法是标注了 @ Adaptive 注解的,因此会生成代理类,然后代理类会根据 Invoker 里面的 URL 参数得知具体的协议,然后通过 Dubbo SPI 机制选择对应的实现类进行 export,而这个方法就会调用 InjvmProtocol#export 方法

InjvmProtocol:实际上就是具体实现类层层封装, invoker 其实是由 Javassist 创建的,具体创建过程 proxyFactory.getInvoker 就不做分析了,对 Javassist 有兴趣的同学自行去了解,之后可能会写一篇,至于 dubbo 为什么用 javassist 而不用 jdk 动态代理是因为 javassist 快

为什么封装成invoker:至于为什么要封装成 invoker 其实就是想屏蔽调用的细节,统一暴露出一个可执行体,这样调用者简单的使用它,向它发起 invoke 调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现

本地暴露存在的意义:因为可能存在同一个 JVM 内部引用自身服务的情况,因此暴露的本地服务在内部调用的时候可以直接消费同一个 JVM 的服务避免了网络间的通信。

一起来看一波exportLocal的时序图:

远程暴露:本机的服务暴露给别的机器的消费者使用

把目光聚焦到 DubboProtocol#export 方法和其内部的openServer()方法上,可以看到这里的关键其实就是打开 Server ,RPC 肯定需要远程调用,这里我们用的是 NettyServer 来监听服务。

再往更细的地方我就不一一分析了,大家感兴趣的拉代码去看吧,看懂大致流程和其中的设计思想最为关键

有道无术,术可成;有术无道,止于术

欢迎大家关注Java之道公众号

好文章,我在看❤️

面试官问我:解释一下Dubbo服务暴露相关推荐

  1. 面试官问我,使用Dubbo有没有遇到一些坑?我笑了。

    作者:肥朝 来自:feichao_java 前言 17年的时候,因为一时冲动没把持住(当然最近也有粉丝叫我再冲动一把再更新一波),结合面试题写了一个系列的Dubbo源码解析.目前公众号大部分粉丝都是之 ...

  2. 面试官问我,Redis分布式锁如何续期?懵了。

    作者:肥朝,来自:肥朝(ID:feichao_java) 前言 上一篇[面试官问我,使用Dubbo有没有遇到一些坑?我笑了.]之后,又有一位粉丝和我说在面试过程中被虐了.鉴于这位粉丝是之前肥朝的老粉丝 ...

  3. 【264期】面试官问:Spring Boot 启动时自动执行代码方式有哪几种?解释一二!...

    点击上方"Java精选",选择"设为星标" 别问别人为什么,多问自己凭什么! 下方有惊喜,留言必回,有问必答! 每一天进步一点点,是成功的开始... 前言 目前 ...

  4. 【240期】面试官问:说说基于 Redis 实现延时队列服务?

    点击上方"Java精选",选择"设为星标" 别问别人为什么,多问自己凭什么! 下方有惊喜,留言必回,有问必答! 每天 08:15 更新文章,每天进步一点点... ...

  5. 面试官问:Kafka 会不会丢消息?怎么处理的?

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! Kafka存在丢消息的问题,消息丢失会发生在Broker, ...

  6. 面试官问我:一个 TCP 连接可以发多少个 HTTP 请求?我竟然回答不上来...

    点击上方"方志朋",选择"设为星标" 做积极的人,而不是积极废人 作者 | 松若章 来源 | https://zhuanlan.zhihu.com/p/6142 ...

  7. 面试官问我:Redis 内存满了怎么办

    转载自 想不到!面试官问我:Redis 内存满了怎么办 Redis占用内存大小 Redis的内存淘汰 LRU算法 LRU在Redis中的实现 LFU算法 问题 Redis占用内存大小 我们知道Redi ...

  8. 美女面试官问我Python如何优雅的创建临时文件,我的回答....

    [摘要] 本故事纯属虚构,如有巧合,他们故事里的美女面试官也肯定没有我的美,请自行脑补... 小P像多数Python自学者一样,苦心钻研小半年,一朝出师投简历. 这不,一家招聘初级Python开发工程 ...

  9. 面试官问你为什么选择做客服_在线客户服务-您的选择

    面试官问你为什么选择做客服 On the Web, news travels fast - and a good customer testimonial is worth its weight in ...

最新文章

  1. 你知道怎么分库分表吗?如何做到永不迁移数据和避免热点吗?
  2. Qt之excel 操作使用说明
  3. Android 多屏显示分析
  4. vue-cli3 一直运行 /sockjs-node/info?t= 解决方案
  5. ASP.NET 导出EXCEL
  6. 面试题整理(机器学习、数据结构)
  7. .net core ——微服务内通信Thrift和Http客户端响应比较
  8. pandas合并concatmerge和plot画图
  9. linux一个vlan配置多个端口映射,Linux 设置 多ip,多vlan
  10. 详解OTT与IPTV的不同之处
  11. mcollective的web控制台---mcomaster搭建
  12. node.js 初体验(转载)
  13. ONAP如何将Open-O和ECOMP数百万行代码合并?
  14. web开发规范 - 图片规范
  15. ubuntu或者Ubuntu Kylin下安装Visual Studio Code
  16. 网络摄像机进行互联网视频直播录像方案的选择,EasyNVS or EasyCloud or EasyGBS?
  17. 初识C语言(三)--最终章,万字解析,趣味讲解完C语言的最后知识点
  18. android 远程视频监控程序源码,详解基于Android已开放源代码的远程视频监控系统教程...
  19. Eggjs入门系列-基础全面讲解(完结)
  20. 用计算机的声音编辑工具录制一段语音信号,传媒2020年7月《影视录音基础》课程考试在线作业考核试题题目【标准答案】...

热门文章

  1. php timesheet,vue版本的timesheet图表
  2. oracle实现mysql的if_【原创】ORACLE的几个函数在MYSQL里面的简单实现
  3. android 视频录制小例子,android 录制视频实例 VideoRecordDemo
  4. html+include设置,html中的include标签是什么?htmlinclude实现配置解析
  5. px4 uavcan linux,PX4开发指南-12.2.2.UAVCAN固件升级
  6. wpf绑定treeview 带查找_如何查找,修复和避免C#.NET中内存泄漏的8个最佳实践
  7. python识图找图_利用python进行识别相似图片(二)
  8. 普通用户安装nginx
  9. C++ static_cast dynamic_cast const_cast reinterpret_cast使用总结
  10. Linux Socket poll