Dubbo之DubboBootstrap源码解析
功能描述
- DubboBootstrap是Dubbo的启动类,包含服务启动、初始化、预处理配置、销毁清理等核心功能
功能分析
核心DubboBootstrap类分析
主要成员变量分析
private static volatile DubboBootstrap instance; //缓存者启动类的实例对象,以static形式存储,便于其它类调用private final AtomicBoolean awaited = new AtomicBoolean(false); //是否等待private final Lock lock = new ReentrantLock();private final Condition condition = lock.newCondition();private final Lock destroyLock = new ReentrantLock(); //销毁清理时用到的锁private final ExecutorService executorService = newSingleThreadExecutor();private final EventDispatcher eventDispatcher = EventDispatcher.getDefaultExtension(); //事件派发器private final ExecutorRepository executorRepository = getExtensionLoader(ExecutorRepository.class).getDefaultExtension(); //线程池仓库private final ConfigManager configManager; //配置管理器private final Environment environment;private ReferenceConfigCache cache; //引用配置的缓存对象private volatile boolean exportAsync; //是否异步暴露private volatile boolean referAsync; //是否异步引用private AtomicBoolean initialized = new AtomicBoolean(false); //初始化标识private AtomicBoolean started = new AtomicBoolean(false); //启动标识private AtomicBoolean ready = new AtomicBoolean(true); //是否已经准备好环境private AtomicBoolean destroyed = new AtomicBoolean(false);private volatile ServiceInstance serviceInstance; //服务实例private volatile MetadataService metadataService; //元数据服务private volatile Set<MetadataServiceExporter> metadataServiceExporters;private List<ServiceConfigBase<?>> exportedServices = new ArrayList<>(); //已经暴露的服务列表private List<Future<?>> asyncExportingFutures = new ArrayList<>(); //异步暴露时使用的Future列表
主要成员方法分析
获取DubboBootstrap的实例对象
public static DubboBootstrap getInstance() { //获取实例(使用单例模式)if (instance == null) {synchronized (DubboBootstrap.class) {if (instance == null) { //synchronized + 双重检查,线程安全且缩小锁的范围instance = new DubboBootstrap();}}}return instance;
}
私有的构造函数
private DubboBootstrap() { //私有的构造函数configManager = ApplicationModel.getConfigManager(); //config对象的本地配置environment = ApplicationModel.getEnvironment(); //获取环境信息DubboShutdownHook.getDubboShutdownHook().register();ShutdownHookCallbacks.INSTANCE.addCallback(new ShutdownHookCallback() { //注册钩子函数,当容器停止时,对DubboBootstrap进行销毁处理@Overridepublic void callback() throws Throwable {DubboBootstrap.this.destroy();}});
}
做初始化
public void initialize() { //初始化if (!initialized.compareAndSet(false, true)) {return; //此处initialized为true时进入,表明是已经初始化过来,就不在初始化}ApplicationModel.initFrameworkExts(); //初始化框架配置startConfigCenter(); //启动配置中心(拉取远程的配置写到本地缓存中)loadRemoteConfigs(); //加载远程配置(包含RegistryConfig、ProtocolConfig)、并写到ConfigManager对应的缓存中checkGlobalConfigs(); //检查Config是否正确startMetadataCenter(); //启动元数据中心initMetadataService(); //创建MetadataService实例(通过SPI接口WritableMetadataService的实例创建)initMetadataServiceExports(); //创建MetadataServiceExporter实例的集合initEventListener(); //将当前对象作为监听器加入到缓存中的监听器列表if (logger.isInfoEnabled()) {logger.info(NAME + " has been initialized!");}
}
启动服务
public DubboBootstrap start() {if (started.compareAndSet(false, true)) {ready.set(false); //设置标志值initialize();//初始化处理if (logger.isInfoEnabled()) {logger.info(NAME + " is starting...");}exportServices(); //暴露服务if (!isOnlyRegisterProvider() || hasExportedServices()) {exportMetadataService(); //暴露元数据registerServiceInstance(); //注册服务到注册中心}referServices(); //引用服务if (asyncExportingFutures.size() > 0) { //服务异步暴露后,更新启动标志new Thread(() -> {try {this.awaitFinish(); //阻塞着等待异步任务完成} catch (Exception e) {logger.warn(NAME + " exportAsync occurred an exception.");}ready.set(true);if (logger.isInfoEnabled()) {logger.info(NAME + " is ready.");}}).start();} else { //服务同步暴露后,更新启动标志ready.set(true);if (logger.isInfoEnabled()) {logger.info(NAME + " is ready.");}}if (logger.isInfoEnabled()) { //dubbo启动完成的日志logger.info(NAME + " has started.");}}return this;
}
做销毁清理
public void destroy() { //做销毁清理工作(包含关联的注册信息、元数据信息、暴露服务信息等)if (destroyLock.tryLock()) { //尝试加锁做清理,保证线程安全try {DubboShutdownHook.destroyAll(); //停机钩子线程做销毁工作if (started.compareAndSet(true, false)&& destroyed.compareAndSet(false, true)) { //在服务已启动且未销毁时,才做清理unregisterServiceInstance(); //会发起远程调用,取消注册的服务,比如若注册中心为zookeeper,则会通过curator,取消注册的服务unexportMetadataService(); //取消元数据暴露unexportServices(); //从ConfigMananer移除暴露的服务缓存unreferServices(); //取消服务引用destroyRegistries(); //销毁注册实例(即关闭注册中心客户端,以及移除注册实例在本地的缓存)DubboShutdownHook.destroyProtocols(); //销毁所有协助,并释放协议所在的资源destroyServiceDiscoveries(); //移除服务实例,即ServiceDiscovery实例clear(); //清除配置信息shutdown(); //停止运行中的线程池release(); //唤醒所有线程,将该执行的任务执行完,然后再做释放处理}} finally {destroyLock.unlock();}}
}
关联GenericEventListener类分析
主要成员变量分析
private final Method onEventMethod; //onEvent(Event)方法对应的Methodprivate final Map<Class<?>, Set<Method>> handleEventMethods; //维护着事件与事件触发的方法的关系
- 代码解析:GenericEventListener是事件监听器,维护着事件以及触发事件的方法
主要成员方法分析
查找处理事件的方法
private Map<Class<?>, Set<Method>> findHandleEventMethods() {Map<Class<?>, Set<Method>> eventMethods = new HashMap<>();of(getClass().getMethods()).filter(this::isHandleEventMethod) //过滤出符合条件处理事件的方法.forEach(method -> {Class<?> paramType = method.getParameterTypes()[0];Set<Method> methods = eventMethods.computeIfAbsent(paramType, key -> new LinkedHashSet<>());methods.add(method);});return eventMethods;
}
执行事件对应的方法
public final void onEvent(Event event) { Class<?> eventClass = event.getClass();handleEventMethods.getOrDefault(eventClass, emptySet()).forEach(method -> {ThrowableConsumer.execute(method, m -> {m.invoke(this, event); //依次执行事件关联的方法});});
}
关联EventListener接口分析
@SPI
@FunctionalInterface
public interface EventListener<E extends Event> extends java.util.EventListener, Prioritized { //事件监听器void onEvent(E event); //事件处理static Class<? extends Event> findEventType(Class<?> listenerClass) { //根据监听器Class查找对应的事件Class(就是查找 EventListener<E extends Event> 中的泛化类型)Class<? extends Event> eventType = null;if (listenerClass != null && EventListener.class.isAssignableFrom(listenerClass)) { //isAssignableFrom判断一个类或接口是否是另一个类超类或父接口eventType = findParameterizedTypes(listenerClass).stream().map(EventListener::findEventType) //找到事件的实际类型.filter(Objects::nonNull).findAny().orElse((Class) findEventType(listenerClass.getSuperclass())); //若都没找到,则找它的父类对应的事件类型}return eventType;}static Class<? extends Event> findEventType(ParameterizedType parameterizedType) { //根据参数化的类型找到事件类型Class<? extends Event> eventType = null;Type rawType = parameterizedType.getRawType(); //获取泛型参数if ((rawType instanceof Class) && EventListener.class.isAssignableFrom((Class) rawType)) { //泛型参数为EventListener进行处理Type[] typeArguments = parameterizedType.getActualTypeArguments(); //获取实际的参数列表for (Type typeArgument : typeArguments) {if (typeArgument instanceof Class) {Class argumentClass = (Class) typeArgument;if (Event.class.isAssignableFrom(argumentClass)) { //找到类型为Event的参数eventType = argumentClass;break;}}}}return eventType;}
}
- 代码解析:EventListener是SPI接口,也是函数式接口,通过事件监听处理对应的事件,类似Handle处理类。该接口继承了java中EventListener,因为所有事件监听器接口都必须扩展的标记接口EventListener。
问题点答疑
-
DubboBootstrap主要负责启动加载哪些信息?是从哪里进入到DubboBootStrap类的?
- 解答:执行逻辑在DubboBootstrapApplicationListener#onApplicationContextEvent中,也就是在spring容器启动后监听容器发布的时间,里面有调用dubboBootstrap.start(); dubbo服务的启动方法
-
DubboBootstrap怎么实现优雅停机?
- 解答:通过在创建DubboBootstrap实例时注册钩子函数,当容器停止时,对DubboBootstrap进行销毁处理,会将相关的清理操作处理,所有的任务处理完,才会关闭服务。
-
java.util.EventListener的功能用途是啥?
- 解答:java中EventListener是一个标记接口,java规定所有的事件都要继承该接口。
-
停机时ShutdownHookCallbacks#addCallback,是怎么进入此处的回调方法的?
- 解答:在DubboShutdownHook#run线程被执行时,就会执行回调方法ShutdownHookCallbacks#callback,会依次执行已经注册的List钩子回调接口的callback方法
归纳总结
- DubboBootstrap类是Dubbo的启动类,主要功能包括:
- Config配置初始化以及合法性检查
- 服务启动、服务注册、服务引用
- 注册钩子、服务销毁时做清理
相关文章:
Dubbo之DubboBootstrap源码解析
功能描述 DubboBootstrap是Dubbo的启动类,包含服务启动、初始化、预处理配置、销毁清理等核心功能 功能分析 核心DubboBootstrap类分析 主要成员变量分析 private static volatile DubboBootstrap instance; //缓存者启动类的实例对象,以static形式…...
SpringBoot + Vue 微人事 项目 (第八天)
基础信息设置 在该页面添加一个大div,然后添加一个tab选项卡,Element UI里面有 把代码复制到大div里面,把里面的label和name属性改成我们想要的,再把tab-click"handleClick"去掉 <div><el-tabs v-model"a…...
人工智能引领图文扫描新趋势
1. 背景和影响 近日,中国大学生服务外包创新创业大赛决赛在江南大学圆满落幕。为满足现代服务产业企业的现实需求,本次竞赛内容设计充分聚焦企业发展中所面临的技术、管理等现实问题,与产业的结合度更紧密,智能文字识别技术是大赛…...
ChatGPT在智能城市规划和交通优化中的应用如何?
智能城市规划和交通优化是应对城市化挑战、提高城市可持续性的重要领域。在这方面,ChatGPT作为一种强大的自然语言处理模型,可以发挥重要作用,帮助实现更智能、高效的城市规划和交通管理。本文将详细探讨ChatGPT在智能城市规划和交通优化中的…...
探索Perfetto:开源性能追踪工具的未来之光
探索Perfetto:开源性能追踪工具的未来之光 1. 引言 A. 介绍Perfetto的背景和作用 随着移动应用、桌面软件和嵌入式系统的不断发展,软件性能优化变得愈发重要。在这个背景下,Perfetto作为一款开源性能追踪工具,日益引起了开发者…...
A*算法图文详解
基本概念 A*算法最早于1964年在IEEE Transactions on Systems Science and Cybernetics中的论文《A Formal Basis for the Heuristic Determination of Minimum Cost Paths》中首次提出。其属于一种经典的启发式搜索方法,所谓启发式搜索,就在于当前搜索…...
[MySQL] — 数据类型和表的约束
目录 数据类型 数据类型分类 数值类型 tinyint类型 bit类型 小数类型 float decimal 字符串类型 char varchar char和varchar的区别 日期和时间类型 enum 和 set 表的约束 空属性 默认值 列描述 zeorfill 主键 创建表时在字段上指定主键 删除主键: 追…...
JetBrains IDE远程开发功能可供GitHub用户使用
JetBrains与GitHub去年已达成合作,提供GitHub Codespaces 与 JetBrains Gateway 之间的集成。 GitHub Codespaces允许用户创建安全、可配置、专属的云端开发环境,此集成意味着您可以通过JetBrains Gateway使用在 GitHub Codespaces 中运行喜欢的IDE进行…...
LVS 负载均衡集群
集群 集群(Cluster)是一组相互连接的计算机或服务器,它们通过网络一起工作以完成共同的任务或提供服务。集群的目标是通过将多台计算机协同工作,提高计算能力、可用性、性能和可伸缩性,适用于大量高并发的场景。 集群…...
Mongodb Ubuntu安装
Mongodb Ubuntu安装 1.更新软件源导入MongoDB的GPG密钥 sudo apt update sudo apt install -y dirmngr wget gnupg apt-transport-https ca-certificates software-properties-common gnupgwget -qO - https://www.mongodb.org/static/pgp/server-6.0.asc | sudo apt-key add…...
【Spring Boot 源码学习】自动装配流程源码解析(下)
自动装配流程源码解析(下) 引言往期内容主要内容4. 排除指定自动配置组件5. 过滤自动配置组件6. 触发自动配置事件 总结 引言 上篇博文,笔者带大家了解了自动装配流程中有关自动配置加载的流程; 本篇将介绍自动装配流程剩余的内…...
基于微信小程序的毕业设计题目200例
个人简介:7 年大厂程序员经历,擅长Java、微信小程序、Python、Android等,大家有这一块的问题可以一起交流! 各类成品 java毕设 。javaweb,ssh,ssm,springboot等等项目框架,源码丰富&…...
【数据管理】什么是数据管理?
文章目录 前言常见内容主题领域数据类型元数据引用数据主数据交易数据 数据类型的特点数据类型之间的关系GIGO数据质量评估 数据质量管理数据治理数据安全 前言 数据管理,即对数据资源的管理。按照 DAMA (国际数据管理协会)的定义࿱…...
[oneAPI] 手写数字识别-LSTM
[oneAPI] 手写数字识别-LSTM 手写数字识别参数与包加载数据模型训练过程结果 oneAPI 比赛:https://marketing.csdn.net/p/f3e44fbfe46c465f4d9d6c23e38e0517 Intel DevCloud for oneAPI:https://devcloud.intel.com/oneapi/get_started/aiAnalyticsToolk…...
通过css设置filter 属性,使整个页面呈现灰度效果,让整个网页变灰
通过css设置filter 属性设置页面整体置灰 效果图: 通过设置 filter 属性为 grayscale(100%),页面中的所有元素都会被应用灰色滤镜效果,使整个页面呈现灰度效果。 <style type"text/css"> html { filter: grayscale(100%); -webkit-f…...
ahooks.js:一款强大的React Hooks库及其API使用教程(一)
一、ahooks.js简介二、ahooks.js安装三、ahooks.js API介绍与使用教程1. useRequest2. useAntdTable3. useSize4. useBoolean5. useToggle6. useHover7. useDebounce8. useEventListener9. useFusionTable10. useKeyPress11. useLoading12. usePrevious13. useForm14. useUpdat…...
拟合圆算法源码(商业)
1、输入一些点 2、执行fitCircle算法 3、输出圆心(x,y)及半径r Box fitCircle(const std::vector<cv::Point2f>& points) {Box box;box.x = 0.0f;box.y = 0.0f;box.r = 0.0f;if (points.size() < 3){return box;}int i = 0;double X1 = 0;double Y1 = 0;doubl…...
第一章 IRIS 编程简介
文章目录 第一章 IRIS 编程简介简介ClassesRoutines 第一章 IRIS 编程简介 简介 IRIS 是一个高性能多模型数据平台,具有内置的通用编程语言 ObjectScript,以及对 Python 的内置支持。 IRIS 支持多进程并提供并发控制。每个进程都可以直接、高效地访问…...
Leetcode-每日一题【剑指 Offer 32 - III. 从上到下打印二叉树 III】
题目 请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。 例如: 给定二叉树: [3,9,20,null,null,15,7], 3 / \ 9 20…...
.NET应用UI组件DevExpress XAF v23.1 - 全新的日程模块
DevExpress XAF是一款强大的现代应用程序框架,允许同时开发ASP.NET和WinForms。DevExpress XAF采用模块化设计,开发人员可以选择内建模块,也可以自行创建,从而以更快的速度和比开发人员当前更强有力的方式创建应用程序。 在新版中…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
