面试官问我:解释一下Dubbo服务暴露
共 5197字,需浏览 11分钟
·
2021-09-13 16:37
今天我们要分析的就是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这个方法看,这个方法很长,我们就不一步步的去看了,滑到方法最后这里:
本地暴露和远程暴露
有道无术,术可成;有术无道,止于术
欢迎大家关注Java之道公众号
好文章,我在看❤️