当前位置: 首页 > news >正文

Skywalking流程分析_3(服务的准备、启动、关闭)

前文将SkyWalkingAgent.premain中的:

  • SnifferConfigInitializer.initializeCoreConfig(agentArgs)
  • pluginFinder = new PluginFinder(new PluginBootstrap().loadPlugins())这两个方法分析完毕,下面继续分析premain方法其余部分

创建byteBuddy

final ByteBuddy byteBuddy = new ByteBuddy().with(TypeValidation.of(Config.Agent.IS_OPEN_DEBUGGING_CLASS));

设置哪里类进行忽略

AgentBuilder agentBuilder = new AgentBuilder.Default(byteBuddy).ignore(nameStartsWith("net.bytebuddy.").or(nameStartsWith("org.slf4j.")).or(nameStartsWith("org.groovy.")).or(nameContains("javassist")).or(nameContains(".asm.")).or(nameContains(".reflectasm.")).or(nameStartsWith("sun.reflect")).or(allSkyWalkingAgentExcludeToolkit()).or(ElementMatchers.isSynthetic()));

把一些必要的类注入到BootstrapClassLoader中

agentBuilder = BootstrapInstrumentBoost.inject(pluginFinder, instrumentation, agentBuilder, edgeClasses);

这里先不做详细的分析,先分析不是由BootstrapClassLoader加载的类,然后回过头来分析这个,否则不好理解

启动服务

//将BootService的这些服务依次进行启动
ServiceManager.INSTANCE.boot();
public void boot() {//通过spi加载实现了BootService接口的服务bootedServices = loadAllServices();//将BootService的这些服务依次进行启动prepare();startup();onComplete();
}

所谓的服务就是实现了org.apache.skywalking.apm.agent.core.boot.BootService接口的实现类,可以看到此接口定义了一系列的生命周期的操作

public interface BootService {//准备void prepare() throws Throwable;//启动void boot() throws Throwable;//启动完成void onComplete() throws Throwable;//关闭void shutdown() throws Throwable;/*** {@code BootService}s with higher priorities will be started earlier, and shut down later than those {@code BootService}s with lower priorities.** @return the priority of this {@code BootService}.*/default int priority() {return 0;}
}

spi加载实现BootService接口的服务

private Map<Class, BootService> loadAllServices() {Map<Class, BootService> bootedServices = new LinkedHashMap<>();List<BootService> allServices = new LinkedList<>();//通过spi机制加载实现了BootService接口的服务load(allServices);for (final BootService bootService : allServices) {Class<? extends BootService> bootServiceClass = bootService.getClass();//判断有没有默认实现boolean isDefaultImplementor = bootServiceClass.isAnnotationPresent(DefaultImplementor.class);if (isDefaultImplementor) {//如果有默认实现,则放入进去if (!bootedServices.containsKey(bootServiceClass)) {bootedServices.put(bootServiceClass, bootService);} else {//ignore the default service}} else {//判断是不是覆盖实现OverrideImplementor overrideImplementor = bootServiceClass.getAnnotation(OverrideImplementor.class);//既没有@DefaultImplementor,也没有@OverrideImplementorif (overrideImplementor == null) {if (!bootedServices.containsKey(bootServiceClass)) {bootedServices.put(bootServiceClass, bootService);} else {throw new ServiceConflictException("Duplicate service define for :" + bootServiceClass);}} else {//没有@DefaultImplementor,但是有@OverrideImplementor,就是覆盖默认实现Class<? extends BootService> targetService = overrideImplementor.value();//当前 覆盖实现 要覆盖的 默认实现 已经被加载进来 if (bootedServices.containsKey(targetService)) {//被覆盖的默认实现上必须要有@DefaultImplementor才能够使用 被覆盖实现boolean presentDefault = bootedServices.get(targetService).getClass().isAnnotationPresent(DefaultImplementor.class);if (presentDefault) {bootedServices.put(targetService, bootService);} else {throw new ServiceConflictException("Service " + bootServiceClass + " overrides conflict, " + "exist more than one service want to override :" + targetService);}} else {//当前 覆盖实现 要覆盖的 默认实现 还没有被加载进来,这时就把这个 覆盖实现 当做是其服务的 默认实现bootedServices.put(targetService, bootService);}}}}return bootedServices;
}

通过spi机制加载实现了BootService接口的服务

void load(List<BootService> allServices) {for (final BootService bootService : ServiceLoader.load(BootService.class, AgentClassLoader.getDefault())) {allServices.add(bootService);}
}

既然是spi加载,那么需要看下spi的文件,在META-INF.services下的org.apache.skywalking.apm.agent.core.boot.BootService文件

org.apache.skywalking.apm.agent.core.remote.TraceSegmentServiceClient
org.apache.skywalking.apm.agent.core.context.ContextManager
org.apache.skywalking.apm.agent.core.sampling.SamplingService
org.apache.skywalking.apm.agent.core.remote.GRPCChannelManager
org.apache.skywalking.apm.agent.core.jvm.JVMMetricsSender
org.apache.skywalking.apm.agent.core.jvm.JVMService
org.apache.skywalking.apm.agent.core.remote.ServiceManagementClient
org.apache.skywalking.apm.agent.core.context.ContextManagerExtendService
org.apache.skywalking.apm.agent.core.commands.CommandService
org.apache.skywalking.apm.agent.core.commands.CommandExecutorService
org.apache.skywalking.apm.agent.core.profile.ProfileTaskChannelService
org.apache.skywalking.apm.agent.core.profile.ProfileSnapshotSender
org.apache.skywalking.apm.agent.core.profile.ProfileTaskExecutionService
org.apache.skywalking.apm.agent.core.meter.MeterService
org.apache.skywalking.apm.agent.core.meter.MeterSender
org.apache.skywalking.apm.agent.core.context.status.StatusCheckService
org.apache.skywalking.apm.agent.core.remote.LogReportServiceClient
org.apache.skywalking.apm.agent.core.conf.dynamic.ConfigurationDiscoveryService
org.apache.skywalking.apm.agent.core.remote.EventReportServiceClient
org.apache.skywalking.apm.agent.core.ServiceInstanceGenerator

服务结构

  • 上面的代码在加载时分成了默认实现和覆盖实现。结构是默认实现(DefaultTest)实现Test接口(ServiceTest),覆盖实现(OverrideTest)继承默认实现
  • 接口和默认实现合并,默认实现标注@DefaultImplementor,覆盖实现继承默认实现并标注@OverrideImplementor(value=默认实现.class)

以日志报告服务举例

//这是默认实现
@DefaultImplementor
public class LogReportServiceClient implements BootService
//覆盖实现
@OverrideImplementor(LogReportServiceClient.class)
public class KafkaLogReporterServiceClient extends LogReportServiceClient

通过spi加载了实现BootService接口的服务,然后放到了bootedServices中,下面就是在prepare、startup、onComplete方法中依次的调用这些服务

public void shutdown() {bootedServices.values().stream().sorted(Comparator.comparingInt(BootService::priority).reversed()).forEach(service -> {try {service.shutdown();} catch (Throwable e) {LOGGER.error(e, "ServiceManager try to shutdown [{}] fail.", service.getClass().getName());}});
}private void prepare() {bootedServices.values().stream().sorted(Comparator.comparingInt(BootService::priority)).forEach(service -> {try {service.prepare();} catch (Throwable e) {LOGGER.error(e, "ServiceManager try to pre-start [{}] fail.", service.getClass().getName());}});
}private void startup() {bootedServices.values().stream().sorted(Comparator.comparingInt(BootService::priority)).forEach(service -> {try {service.boot();} catch (Throwable e) {LOGGER.error(e, "ServiceManager try to start [{}] fail.", service.getClass().getName());}});
}private void onComplete() {for (BootService service : bootedServices.values()) {try {service.onComplete();} catch (Throwable e) {LOGGER.error(e, "Service [{}] AfterBoot process fails.", service.getClass().getName());}}
}

总结

服务结构:

  • 服务要实现BootService接口
  • 服务如果只有一种实现,直接创建一个类即可
  • 如果有多种实现
    • 默认实现使用@DefaultImplementor
    • 覆盖实现使用@OverrideImplementor
      加载过程:
  • SPI加载所有实现BootService接口的服务
  • 根据服务实现模式进行加载
    • 两个注解都没有的服务直接加入服务
    • @DefaultImplementor修饰的服务直接加入集合
    • @OverrideImplementor
      • value指向的服务有@DefaultImplementor,则覆盖
      • value指向的服务没有@DefaultImplementor,则报错

后文介绍的是插件的具体结构和如何识别不同版本而是使用不同插件的技巧

相关文章:

Skywalking流程分析_3(服务的准备、启动、关闭)

前文将SkyWalkingAgent.premain中的&#xff1a; SnifferConfigInitializer.initializeCoreConfig(agentArgs)pluginFinder new PluginFinder(new PluginBootstrap().loadPlugins())这两个方法分析完毕&#xff0c;下面继续分析premain方法其余部分 创建byteBuddy final By…...

mysql中的各种日志文件redo log、undo log和binlog

mysql中的各种日志文件redo log、undo log和binlog mysql中的各种日志文件redo log、undo log和binlog1.MySQL日志文件类型2.redo log日志2.1 作用2.2工作原理&#xff1a;2.3详解 3.undo log日志4.binlog日志5.总结 mysql中的各种日志文件redo log、undo log和binlog 1.MySQL…...

【电视剧-长相思】经典语录

小编看了这么长时间的电视剧&#xff0c;突然感觉摘抄经典语录最有成就感&#xff0c;嘿嘿&#xff0c;下面是我在《长相思》&#xff08;第一季&#xff09;中感觉好的一些语录&#xff0c;语录是乱序排列哈 玟小六&#xff1a;我怕寂寞&#xff0c;寻不到长久的相依&#xff…...

串口通信原理及应用

Content 1. 前言介绍2. 连接方式3. 数据帧格式4. 代码编写 1. 前言介绍 串口通信是一种设备间非常常用的串行接口&#xff0c;以比特位的形式发送或接收数据&#xff0c;由于成本很低&#xff0c;容易使用&#xff0c;工程师经常使用这种方式来调试 MCU。 串口通信应用广泛&a…...

python爬取穷游网景点评论

爬取穷游网的景点评论数据&#xff0c;使用selenium爬取edge浏览器的网页文本数据。 同程的评论数据还是比较好爬取&#xff0c;不像大众点评需要你登录验证杂七杂八的&#xff0c;只需要找准你想要爬取的网页链接就能拿到想要的文本数据。 这里就不得不提一下爬取过程中遇到的…...

Phar 文件上传以及反序列化

1.phar反序列化 触发条件&#xff1a; 1、能将phar文件上传 2、可利用函数 stat、fileatime、filectime、file_exists、file_get_contents、file_put_contents、file、filegroup、fopen、fileinode、filemtime、fileowner、fileperms、is_dir、is_executable、is_file、is_link…...

面试其他注意事项

面试其他注意事项 一、面试反问 这个岗位的日常工作和主要职责是什么&#xff1f;咱们这边主要负责什么业务&#xff0c;用到了哪些技术呢&#xff1f;对于我们校招生有没有培养体系呢&#xff1f;脱产培训&#xff0c;还是边工作边熟悉&#xff1f;会有导师带嘛&#xff1f;…...

sklearn 笔记 BallTree/KD Tree

由NearestNeighbors类包装 1 主要使用方法 sklearn.neighbors.BallTree(X, leaf_size40, metricminkowski, **kwargs) X数据集中的点数leaf_size改变 leaf_size 不会影响查询的结果&#xff0c;但可以显著影响查询的速度和构建树所需的内存metric用于距离计算的度量。默认为…...

ConstraintLayout使用详解

作为一名程序员&#xff0c;可能会经历以下难受的事情&#xff1a; 解决难以调试的代码错误处理复杂的代码库和维护遗留代码修改已经存在很长时间的代码&#xff0c;需要考虑兼容性和稳定性长时间工作&#xff0c;缺乏身体运动和社交互动&#xff0c;导致压力和孤独感遇到不能…...

Java8Stream快速使用

将List集合存入流中 List<String> list new ArrayList<>();list.add("张一");list.add("张二");list.add("张三");list.add("李四");list.add("赵五");list.add("张六");list.add("王八"…...

work环境配置

1.计算机右键找到属性 2.配置环境变量 3.新加环境变量 4.修改环境变量path .bat文件内容 php ApplicationsChatstart_register.php ApplicationsChatstart_gateway.php ApplicationsChatstart_businessworker.php pause...

Flutter应用-使用sqflite升级数据库

文章目录 问题描述具体做法代码示例更多条件限制升级 数据库迁移和备份简介数据库迁移数据库备份 问题描述 使用fluttter开发的应用程序发布后&#xff0c;发现数据库有些设计不合理。如何来更新数据库呢&#xff1f; 使用sqflite来处理数据库&#xff0c;但是第一版软件发布后…...

集群搭建(redis7)

一、主从复制(replica)&#xff08;不推荐&#xff09; 介绍 主从复制 mmaster以写为主&#xff0c;slave以读为主当master数据变化时&#xff0c;自动将新的数据异步同步到其他slave数据库 读写分离down机恢复数据备份水平扩容支撑高并发 基本操作 配从不配主 权限细节 maste…...

高能分享:软件测试十大必问面试题(附带答案)

1 介绍之前负责的项目 参考答案&#xff1a;先大概描述一下这个项目是做什么的&#xff08;主要功能&#xff09;&#xff0c;包括哪些模块&#xff0c;是什么架构的&#xff08;B/S、C/S、移动端&#xff1f;&#xff09;&#xff0c;你在其中负责哪些模块的测试。期间经历了几…...

Java 反射设置List属性

使用 Java 反射可以动态地设置对象的属性值&#xff0c;包括 List 类型的属性。以下是一个示例代码&#xff0c;演示如何通过反射设置 List 类型的属性&#xff1a; 假设有一个类 Person&#xff0c;包含一个 List 类型的属性 names&#xff1a; java public class Person { …...

wpf devexpress Property Grid创建属性定义

WPF Property Grid控件使用属性定义定义如何做和显示 本教程示范如何绑定WP Property Grid控件到数据和创建属性定义。 执行如下步骤 第一步-创建属性定义 添加PropertyGridControl组件到项目。 打开工具箱在vs&#xff0c;定位到DX.23.1: Data 面板&#xff0c;选择Prope…...

78.子集--77.组合

78&#xff0c;子集 递归 class Solution(object):def subsets(self, nums):""":type nums: List[int]:rtype: List[List[int]]"""# 结果ans[]# 临时结果dp_[]def dfs(nums,index):if indexlen(nums):# 保存结果co_dpdp_[:]ans.append(co_dp)r…...

【C++】模版-初阶

目录 泛型编程--模版 函数模版 类模版 泛型编程--模版 函数模版 如何实现一个通用的交换函数呢?void Swap(int& left, int& right){int temp left;left right;right temp;}void Swap(double& left, double& right){double temp left;left right;righ…...

【JavaEE初阶】 TCP服务器与客户端的搭建

文章目录 &#x1f332;前言&#x1f334;ServerSocket API&#x1f384;Socket API&#x1f340;TCP中的长短连接&#x1f38d;建立TCP回显客户端与服务器&#x1f6a9;TCP搭建服务器&#x1f6a9;TCP搭建客户端&#x1f6a9;通信过程展示&#xff1a; &#x1f333;多个客户端…...

23111710[含文档+PPT+源码等]计算机毕业设计基于SpringBoot的体育馆场地预约赛事管理系统的设计

文章目录 **软件开发环境及开发工具&#xff1a;****功能介绍&#xff1a;****论文截图&#xff1a;****数据库&#xff1a;****实现&#xff1a;****代码片段&#xff1a;** 编程技术交流、源码分享、模板分享、网课教程 &#x1f427;裙&#xff1a;776871563 软件开发环境及…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

华硕a豆14 Air香氛版,美学与科技的馨香融合

在快节奏的现代生活中&#xff0c;我们渴望一个能激发创想、愉悦感官的工作与生活伙伴&#xff0c;它不仅是冰冷的科技工具&#xff0c;更能触动我们内心深处的细腻情感。正是在这样的期许下&#xff0c;华硕a豆14 Air香氛版翩然而至&#xff0c;它以一种前所未有的方式&#x…...

JavaScript 数据类型详解

JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型&#xff08;Primitive&#xff09; 和 对象类型&#xff08;Object&#xff09; 两大类&#xff0c;共 8 种&#xff08;ES11&#xff09;&#xff1a; 一、原始类型&#xff08;7种&#xff09; 1. undefined 定…...

代码规范和架构【立芯理论一】(2025.06.08)

1、代码规范的目标 代码简洁精炼、美观&#xff0c;可持续性好高效率高复用&#xff0c;可移植性好高内聚&#xff0c;低耦合没有冗余规范性&#xff0c;代码有规可循&#xff0c;可以看出自己当时的思考过程特殊排版&#xff0c;特殊语法&#xff0c;特殊指令&#xff0c;必须…...

软件工程 期末复习

瀑布模型&#xff1a;计划 螺旋模型&#xff1a;风险低 原型模型: 用户反馈 喷泉模型:代码复用 高内聚 低耦合&#xff1a;模块内部功能紧密 模块之间依赖程度小 高内聚&#xff1a;指的是一个模块内部的功能应该紧密相关。换句话说&#xff0c;一个模块应当只实现单一的功能…...

【PX4飞控】mavros gps相关话题分析,经纬度海拔获取方法,卫星数锁定状态获取方法

使用 ROS1-Noetic 和 mavros v1.20.1&#xff0c; 携带经纬度海拔的话题主要有三个&#xff1a; /mavros/global_position/raw/fix/mavros/gpsstatus/gps1/raw/mavros/global_position/global 查看 mavros 源码&#xff0c;来分析他们的发布过程。发现前两个话题都对应了同一…...

C++11 constexpr和字面类型:从入门到精通

文章目录 引言一、constexpr的基本概念与使用1.1 constexpr的定义与作用1.2 constexpr变量1.3 constexpr函数1.4 constexpr在类构造函数中的应用1.5 constexpr的优势 二、字面类型的基本概念与使用2.1 字面类型的定义与作用2.2 字面类型的应用场景2.2.1 常量定义2.2.2 模板参数…...

Qt 按钮类控件(Push Button 与 Radio Button)(1)

文章目录 Push Button前提概要API接口给按钮添加图标给按钮添加快捷键 Radio ButtonAPI接口性别选择 Push Button&#xff08;鼠标点击不放连续移动快捷键&#xff09; Radio Button Push Button 前提概要 1. 之前文章中所提到的各种跟QWidget有关的各种属性/函数/方法&#…...

在MobaXterm 打开图形工具firefox

目录 1.安装 X 服务器软件 2.服务器端配置 3.客户端配置 4.安装并打开 Firefox 1.安装 X 服务器软件 Centos系统 # CentOS/RHEL 7 及之前&#xff08;YUM&#xff09; sudo yum install xorg-x11-server-Xorg xorg-x11-xinit xorg-x11-utils mesa-libEGL mesa-libGL mesa-…...