目录
- 16-模块发布器发布服务全过程
- 16.1 简介
- 16.2 导出服务的入口
- 16.3 服务配置导出服务
16-模块发布器发布服务全过程
16.1 简介
Dubbo做为服务治理框架,比较核心的就是服务相关的概念,这里我先贴个找到的关于Dubbo工作原理的架构图:
如果按完整服务启动与订阅的顺序我们可以归结为以下6点:
- 导出服务(提供者)
- 服务提供方通过指定端口对外暴露服务
- 注册服务(提供者)
- 提供方向注册中心注册自己的信息
- (服务发现)-订阅服务(消费者)
- 服务调用方通过注册中心订阅自己感兴趣的服务
- (服务发现)-服务推送(消费者)
- 注册中心向调用方推送地址列表
- 调用服务(消费者调用提供者)
- 调用方选择一个地址发起RPC调用
- 监控服务
- 服务提供方和调用方的统计数据由监控模块收集展示
上面的完整的服务启动订阅与调用流程不仅仅适用于Dubbo 同样也适用于其他服务治理与发现的模型, 一般服务发现与服务调用的思路就是这样的,我们将以上内容扩展,暴漏服务可以使用http,tcp,udp等各种协议,注册服务可以注册到Redis,Dns,Etcd,Zookeeper等注册中心中,订阅服务可以主动去注册中心查询服务列表,服务发现可以让注册中心将服务数据动态推送给消费者.Dubbo其实就是基于这种简单的服务模型来扩展出各种功能的支持,来满足服务治理的各种场景,了解了这里可能各位同学就想着自行开发一个简单的微服务框架了。
回到主题,从以上的服务完整发布调用流程可以看到,所有的功能都是由导出服务(提供者)开始的,只有提供者先提供了服务才可以有真正的服务让消费者调用。
之前的博客内容 链接:<<12-全局视野来看Dubbo3.0.8的服务启动生命周期>> 我们了解了 DefaultModuleDeployer模块器启动的流程,其中在start代码的模版方法中开始了导出服务的功能,这里我们来详细看下服务发布的全过程:
入口代码: DefaultModuleDeployer的发布服务方法
private void exportServices() {
//从配置管缓存中查询缓存的所有的服务配置然后逐个服务发布
for (ServiceConfigBase sc : configManager.getServices()) {
exportServiceInternal(sc);
}
}
16.2 导出服务的入口
入口代码: DefaultModuleDeployer的发布服务方法
private void exportServices() {
//从配置管缓存中查询缓存的所有的服务配置然后逐个服务发布
for (ServiceConfigBase sc : configManager.getServices()) {
exportServiceInternal(sc);
}
}
主要流程为遍历初始化的服务配置列表然后逐个服务开始到处
内部导出服务代码:
exportServiceInternal方法:
private void exportServiceInternal(ServiceConfigBase sc) {
ServiceConfig<?> serviceConfig = (ServiceConfig<?>) sc;
//服务配置刷新 配置优先级覆盖
if (!serviceConfig.isRefreshed()) {
serviceConfig.refresh();
}
//服务已经导出过了就直接返回
if (sc.isExported()) {
return;
}
//是否异步方式导出 全局配置或者服务级其中一个配置了异步则异步处理
if (exportAsync || sc.shouldExportAsync()) {
//异步其实就是使用线程来导出服务serviceExportExecutor
ExecutorService executor = executorRepository.getServiceExportExecutor();
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
if (!sc.isExported()) {
sc.export();
exportedServices.add(sc);
}
} catch (Throwable t) {
logger.error(getIdentifier() + " export async catch error : " + t.getMessage(), t);
}
}, executor);
asyncExportingFutures.add(future);
} else {
//同步导出服务
if (!sc.isExported()) {
sc.export();
exportedServices.add(sc);
}
}
}
这个逻辑里面做了一些基本的操作,可以直接看注释然后调用ServiceConfig的export的来导出服务,继续往后看服务配置的导出服务方法。
16.3 服务配置导出服务
核心的服务导出代码是在服务配置中来做的ServiceConfig的 export() 方法
ServiceConfig的 export() 方法代码如下:
public void export() {
//已经导出过服务直接放那会
if (this.exported) {
return;
}
// ensure start module, compatible with old api usage
//确保模块启动了(基本的初始化操作执行了)
getScopeModel().getDeployer().start();
//悲观锁
synchronized (this) {
//双重校验
if (this.exported) {
return;
}
//配置是否刷新 前面初始化时候已经刷新过配置
if (!this.isRefreshed()) {
this.refresh();
}
//服务导出配置配置为false则不导出
if (this.shouldExport()) {
this.init();
if (shouldDelay()) {
doDelayExport();
} else {
doExport();
}
}
}
}