Dubbo 3.2版本分析Provider启动时操作

Dubbo 3.2版本分析Provider启动时操作

  • 前言
  • 例子
  • 分析
    • onStarting 模块
    • doStart 模块
  • 小结

前言

上一篇文章,我们分析了 Dubbo 3.2 版本在 Provider 启动前的操作流程,这次我们具体分析具体它的启动过程,揭开它的神秘面纱。

例子

这里我们还是以provider启动的Demo为入口,进行分析。如下,为Dubbo服务暴漏出来的接口:

public interface DemoService {String sayHello(String name);
}

DemoServiceImpl为Dubbo provider

public class DemoServiceImpl implements DemoService {private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);@Overridepublic String sayHello(String name) {logger.info("Hello " + name + ", request from consumer: "+ RpcContext.getServiceContext().getRemoteAddress());return "Hello " + name + ", response from provider: "+ RpcContext.getServiceContext().getLocalAddress();}}


Application为服务的启动类

public class Application {private static final String REGISTRY_URL = "zookeeper://sr-1-zk-cluster-1.gz.cvte.cn:2181";public static void main(String[] args) {startWithBootstrap();}private static void startWithBootstrap() {ServiceConfig<DemoServiceImpl> service = new ServiceConfig<>();service.setInterface(DemoService.class);service.setRef(new DemoServiceImpl());DubboBootstrap bootstrap = DubboBootstrap.getInstance();bootstrap.application(new ApplicationConfig("dubbo-api-provider")).registry(new RegistryConfig(REGISTRY_URL)).protocol(new ProtocolConfig(CommonConstants.DUBBO, -1)).service(service).start().await();}
}

分析

上文分析过设置 application -> 设置 registry -> 设置 protocol -> 设置 serviceConfig 的流程了,这次我们进入 start 方法。

  1. 进入 start 方法后,最终来到 applicationDeployer.start() 这里。关于 applicationDeployer,它申明是ApplicationDeployer 类型,默认情况下,具体实现为 DefaultApplicationDeployer,关于它们的类结构如图1所示。
  2. Dubbo 3.0 把服务的发布流程进行了抽象,引入了 **Deployer **的概念,负责应用的的初始化和启动。除了 start 方法,其他方法如图2所示。
public DubboBootstrap start() {this.start(true);return this;}/*** Start dubbo application** @param wait If true, wait for startup to complete, or else no waiting.* @return*/public DubboBootstrap start(boolean wait) {Future future = applicationDeployer.start();if (wait) {try {future.get();} catch (Exception e) {throw new IllegalStateException("await dubbo application start finish failure", e);}}return this;}

图1
图2

  1. 接着,我们具体看看 DefaultApplicationDeployer对 start 方法的具体实现。
  2. 这里先进行服务发布状态的判断,通过 AbstractDeployer类里定义的一个共享的成员变量进行判断,默认值是 PENDING

private volatile DeployState state = PENDING;

  1. Dubbo 3.0 引入了领域模型的概念,那么在这里会先判断是否由新加入的模型而重新调用启动过程。判断方式见 hasPendingModule 方法。其中 applicationModel.getModuleModels() 会返回一个线程安全的读写队列。

private final List moduleModels = new CopyOnWriteArrayList<>();

  1. 这里我们是刚启动的状态,所以会 ModuleModel 默认状态即 **PENDING,hasPendingModule **的结果为ture。
  2. 进入 isStarting 方法,同样判断是判断 state,此时还是为 PENDING,所以结果为false。关于 startModules 方法的分析,我们放在后边讲。
  3. 再完后,我们可以看到三个被封装好的流程: onStarting()、 initialize()、doStart(),分别进行服务启动状态的设置、服务启动的初始化,启动各个领域模型。针对这个三个模快,我们在后文继续分析。
public Future start() {synchronized (startLock) {if (isStopping() || isStopped() || isFailed()) {throw new IllegalStateException(getIdentifier() + " is stopping or stopped, can not start again");}try {// maybe call start again after add new module, check if any new moduleboolean hasPendingModule = hasPendingModule();if (isStarting()) {// currently, is starting, maybe both start by module and application// if it has new modules, start themif (hasPendingModule) {startModules();}// if it is starting, reuse previous startFuturereturn startFuture;}// if is started and no new module, just returnif (isStarted() && !hasPendingModule) {return CompletableFuture.completedFuture(false);}// pending -> starting : first start app// started -> starting : re-start apponStarting();initialize();doStart();} catch (Throwable e) {onFailed(getIdentifier() + " start failure", e);throw e;}return startFuture;}}private boolean hasPendingModule() {boolean found = false;for (ModuleModel moduleModel : applicationModel.getModuleModels()) {if (moduleModel.getDeployer().isPending()) {found = true;break;}}return found;
}

onStarting 模块

  1. 这里进来还是先进行状态的判断,如果既不是处于准备中状态或者启动过的状态,则return。
  2. 接着,通过 setStarting 方法修改我们的stateSTARTING 状态。
  3. 这里还会去启动监听者,listeners 为 AbstractDeployer类中的成员变量

protected List<DeployListener> listeners = new CopyOnWriteArrayList<>();

  1. 关于它的赋值有两个时机,这里可以回顾我们的例子中获取 DubboBootstrap 对象时的代码,这里在创建的过程中,会去加载两个监听器。

DubboBootstrap bootstrap = DubboBootstrap.getInstance();

  1. 如下面代码所示,一个是通过我们 SPI 机制引入的 ExporterDeployListener,另一个是用于监听服务启动过程的 DeployListenerAdapter,不过可能是考虑便于后边拓展,这里 onStarting 方法目前暂未做实现。
  2. 最后,构造一个异步线程池赋值给 startFuture 变量,该线程池可用于服务启动、配置加载等事件状态的执行。

private volatile CompletableFuture startFuture;

private void onStarting() {// pending -> starting// started -> startingif (!(isPending() || isStarted())) {return;}setStarting();startFuture = new CompletableFuture();if (logger.isInfoEnabled()) {logger.info(getIdentifier() + " is starting.");}}protected void setStarting() {this.state = STARTING;for (DeployListener<E> listener : listeners) {try {listener.onStarting(scopeModel);} catch (Throwable e) {logger.error(COMMON_MONITOR_EXCEPTION,"","",getIdentifier() + " an exception occurred when handle starting event",e);}}}// DeployListenerAdapter
applicationDeployer.addDeployListener(new DeployListenerAdapter<ApplicationModel>() {@Overridepublic void onStarted(ApplicationModel scopeModel) {notifyStarted(applicationModel);}@Overridepublic void onStopped(ApplicationModel scopeModel) {notifyStopped(applicationModel);}@Overridepublic void onFailure(ApplicationModel scopeModel, Throwable cause) {notifyStopped(applicationModel);}}); // ExporterDeployListener
public class ExporterDeployListener implements ApplicationDeployListener, Prioritized {protected volatile ConfigurableMetadataServiceExporter metadataServiceExporter;@Overridepublic void onInitialize(ApplicationModel scopeModel) {}@Overridepublic void onStarting(ApplicationModel scopeModel) {}// ....}

doStart 模块

  1. 在执行 initialize 模块初始化后,最终是 doStart 模块,这里先启动 内部的模块模型 即 DefaultModuleDeployer 实例,这里同样会把 **DefaultModuleDeployer **的状态先设置为 STARTING。
  2. 注意,前面设置的是DefaultApplicationDeployer 的状态,跟这里的模块的状态还不一样。
  3. 然后会遍历所有的模块列表,可能有些业务场景自己拓展了模块吧,这里会判断它们是否出于准备状态,然后一起启动。
private void doStart() {startModules();
}private void startModules() {// ensure init and start internal module firstprepareInternalModule();// filter and start pending modules, ignore new module during starting, throw exception of module startfor (ModuleModel moduleModel : applicationModel.getModuleModels()) {if (moduleModel.getDeployer().isPending()) {moduleModel.getDeployer().start();}}}

小结

本文分析了 Dubbo 3.2 版本分析Provider启动时的流程,会先启动 ApplicationDeployer 类型实例,在执行 state( onStarting 方法) 更新流程后,进行初始化**( initialize 方法),最后然后是执行启动流程( do start 方法)**。在 do start 方法里才又先启动我们的内部模块,再遍历所有的模块列表,把所有处于准备状态的模块进行启动。最后,关于 initialize 方法由于涉及流程很长,为了保证文章可读性,这里笔者暂时先不展开,也算留个悬念,下一篇我们继续分析它。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/639150.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【ZYNQ入门】第八篇、基于Lwip构建TCP服务器

目录 第一部分、基础知识 1、小白入门必看文章 2、什么是Lwip&#xff1f; 3、什么是TCP/IP协议&#xff1f; 4、MAC地址、IP地址、子网掩码、网关 4.1、MAC地址 4.2、IP地址 4.3、子网掩码 4.4、网关 第二部分、硬件搭建 第三部分、软件代码 1、SDK工程的建立 2、…

数据结构与算法-二叉树-从中序与后序遍历序列构造二叉树

从中序与后序遍历序列构造二叉树 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7], postorder …

云盘后端分析

1.验证码 用的是外面找的 2.发送邮箱验证码 配置邮箱的授权码 我们在发送邮箱的时候&#xff0c;需要把那个值传到数据库中&#xff0c;数据库中有它的状态&#xff0c;我们需要根据状态判断它是注册还是找回密码 我们在发送邮箱之前&#xff0c;先从session里面得到我们验证…

Rocky Linux 8.9 安装图解

风险告知 本人及本篇博文不为任何人及任何行为的任何风险承担责任&#xff0c;图解仅供参考&#xff0c;请悉知&#xff01;本次安装图解是在一个全新的演示环境下进行的&#xff0c;演示环境中没有任何有价值的数据&#xff0c;但这并不代表摆在你面前的环境也是如此。生产环境…

某度网盘提取下载链接JS逆向分析(一)

本次目标网址如下&#xff0c;使用base64解码后获得 aHR0cHM6Ly9wYW4uYmFpZHUuY29tL3MvMUZsaDBPeGpZamZJTFVZWUQzTm9fVnc 链接提取码为&#xff1a;ly12 本次逆向分析分为上下两篇文章说明&#xff0c;一为讲解如何从原链接通过逆向拿到下载链接&#xff0c;二为逆向登录拿到co…

flink结合Yarn进行部署

1. 什么是Yarn模式部署Flink 独立&#xff08;Standalone&#xff09;模式由 Flink 自身提供资源&#xff0c;无需其他框架&#xff0c;这种方式降低了和其他第三方资源框架的耦合性&#xff0c;独立性非常强。但我们知道&#xff0c;Flink 是大数据计算框架&#xff0c;不是资…

C++学习笔记——指针

1&#xff0c;指针的基本概念 指针的作用&#xff1a;可以通过指针间接访问内存 内存的编号是从0开始记录的&#xff0c;一般用十六进制数字表示可以利用指针变量保存地址 上图中的p就是a变量的指针&#xff0c;也可以记作*a 2&#xff0c;指针变量的定义和使用 指针变量定…

Linux操作系统——理解文件系统

预备知识 到目前为止&#xff0c;我们所学习到的关于文件的操作&#xff0c;全部都是基于文件被打开&#xff0c;被访问&#xff0c;访问期间比较重要的有重定向&#xff0c;缓冲区&#xff0c;一切皆文件&#xff0c;当我们访问完毕的时候需要将文件关闭&#xff0c;关闭时那…

3.RHCSA脚本配置及通过node2改密码

运行脚本发现node2不成功 脚本破解 选第二个 Ctrl x 换行 破解成功后做node2的改密码题 回到redhat, 发现检测程序检测密码题成功,得了8分.

DBA技术栈MongoDB: 数据增改删除

该博文主要介绍mongoDB对文档数据的增加、更新、删除操作。 1.插入数据 以下案例演示了插入单个文档、多个文档、指定_id、指定多个索引以及插入大量文档的情况。在实际使用中&#xff0c;根据需求选择适合的插入方式。 案例1&#xff1a;插入单个文档 db.visitor.insert({…

【蓝桥杯冲冲冲】动态规划初步[USACO2006 OPEN] 县集市

蓝桥杯备赛 | 洛谷做题打卡day13 文章目录 蓝桥杯备赛 | 洛谷做题打卡day13题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示样例说明数据规模与约定 思路&#xff1a;方程&#xff1a; 题解代码我的一些话 [USACO2006 OPEN] 县集市 The County Fair 题目描述 每年…

Threejs实现立体3D园区解决方案及代码

一、实现方案 单独贴代码可能容易混乱&#xff0c;所以这里只讲实现思路&#xff0c;代码放在最后汇总了下。 想要实现一个简单的工业园区、主要包含的内容是一个大楼、左右两片停车位、四条道路以及多个可在道路上随机移动的车辆、遇到停车位时随机选择是否要停车&#xff0…

解决ssh登录Permission denied, please try again

现象截图如下&#xff1a; 确定root的密码是正确的&#xff0c;最后的原因找到了&#xff0c;是远程的服务器&#xff0c;禁用了root账户可以被远程访问的权限。开启操作如下&#xff1a; 1.编辑配置文件 vi /etc/ssh/sshd_config 2.文件中找到PermitRootLogin #PermitRoo…

seaborn可视化示例详解

目录 1、散点图 2、散点图回归线 3、折线图 4、频数柱状图 5、分组散点图 6、箱型图 7、数值分布柱状图 8、频数分布图 9、联合分布图 10、数值分布柱状图 11、相关系数热力图 划重点 少走10年弯路 Seaborn是一个基于Python的数据可视化库&#xff0c;Seaborn提供了许多用…

链表|数据结构|C语言深入学习

什么是链表 离散&#xff0c;就是“分离的、散开的” 链表是什么样子的&#xff1a; 有限个节点离散分配 彼此间通过指针相连 除了首尾节点&#xff0c;每个节点都只有一个前驱节点和一个后继节点 首节点没有前驱结点&#xff0c;尾节点没有后继节点 基本概念术语&#xf…

1.使用分布式文件系统Minio管理文件

分布式文件系统DFS分类 文件系统 文件系统是操作系统用于组织管理存储设备(磁盘)或分区上文件信息的方法和数据结构,负责对文件存储设备空间进行组织和分配,并对存入文件进行保护和检索 文件系统是负责管理和存储文件的系统软件&#xff0c;操作系统通过文件系统提供的接口去…

Docker五部曲之五:通过Docker和GitHub Action搭建个人CICD项目

文章目录 项目介绍Dockerfile解析compose.yml解析Nginx反向代理到容器以及SSL证书设置MySQL的准备工作Spring和环境变量的交互 GitHub Action解析项目测试结语 项目介绍 该项目是一个入门CICD-Demo&#xff0c;它由以下几部分组成&#xff1a; Dockerfile&#xff1a;用于构建…

「 典型安全漏洞系列 」05.XML外部实体注入XXE详解

1. XXE简介 XXE&#xff08;XML external entity injection&#xff0c;XML外部实体注入&#xff09;是一种web安全漏洞&#xff0c;允许攻击者干扰应用程序对XML数据的处理。它通常允许攻击者查看应用程序服务器文件系统上的文件&#xff0c;并与应用程序本身可以访问的任何后…

【Unity小技巧】3D人物移动脚步和跳跃下落音效控制

文章目录 单脚步声多脚步声&#xff0c;跳跃落地音效播放不同材质的多脚步声完结 单脚步声 public AudioClip walkingSound; public AudioClip runningSound;//移动音效 public void MoveSound() {// 如果在地面上并且移动长度大于0.9if (isGround && moveDirection.s…

动物免疫(羊驼免疫)-泰克生物

在过去几十年里&#xff0c;抗体研究和应用的领域已经经历了革命性的变化。在这个进程中&#xff0c;一种特殊来源的抗体 —— 来自骆驼科动物&#xff08;包括羊驼&#xff09;的单链抗体&#xff08;也称纳米抗体&#xff09;引起了全球科学家的广泛关注。 羊驼等骆驼科动物…