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中的: SnifferConfigInitializer.initializeCoreConfig(agentArgs)pluginFinder new PluginFinder(new PluginBootstrap().loadPlugins())这两个方法分析完毕,下面继续分析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工作原理:2.3详解 3.undo log日志4.binlog日志5.总结 mysql中的各种日志文件redo log、undo log和binlog 1.MySQL…...
【电视剧-长相思】经典语录
小编看了这么长时间的电视剧,突然感觉摘抄经典语录最有成就感,嘿嘿,下面是我在《长相思》(第一季)中感觉好的一些语录,语录是乱序排列哈 玟小六:我怕寂寞,寻不到长久的相依ÿ…...

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

python爬取穷游网景点评论
爬取穷游网的景点评论数据,使用selenium爬取edge浏览器的网页文本数据。 同程的评论数据还是比较好爬取,不像大众点评需要你登录验证杂七杂八的,只需要找准你想要爬取的网页链接就能拿到想要的文本数据。 这里就不得不提一下爬取过程中遇到的…...
Phar 文件上传以及反序列化
1.phar反序列化 触发条件: 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…...

面试其他注意事项
面试其他注意事项 一、面试反问 这个岗位的日常工作和主要职责是什么?咱们这边主要负责什么业务,用到了哪些技术呢?对于我们校招生有没有培养体系呢?脱产培训,还是边工作边熟悉?会有导师带嘛?…...
sklearn 笔记 BallTree/KD Tree
由NearestNeighbors类包装 1 主要使用方法 sklearn.neighbors.BallTree(X, leaf_size40, metricminkowski, **kwargs) X数据集中的点数leaf_size改变 leaf_size 不会影响查询的结果,但可以显著影响查询的速度和构建树所需的内存metric用于距离计算的度量。默认为…...
ConstraintLayout使用详解
作为一名程序员,可能会经历以下难受的事情: 解决难以调试的代码错误处理复杂的代码库和维护遗留代码修改已经存在很长时间的代码,需要考虑兼容性和稳定性长时间工作,缺乏身体运动和社交互动,导致压力和孤独感遇到不能…...

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开发的应用程序发布后,发现数据库有些设计不合理。如何来更新数据库呢? 使用sqflite来处理数据库,但是第一版软件发布后…...

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

高能分享:软件测试十大必问面试题(附带答案)
1 介绍之前负责的项目 参考答案:先大概描述一下这个项目是做什么的(主要功能),包括哪些模块,是什么架构的(B/S、C/S、移动端?),你在其中负责哪些模块的测试。期间经历了几…...

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

wpf devexpress Property Grid创建属性定义
WPF Property Grid控件使用属性定义定义如何做和显示 本教程示范如何绑定WP Property Grid控件到数据和创建属性定义。 执行如下步骤 第一步-创建属性定义 添加PropertyGridControl组件到项目。 打开工具箱在vs,定位到DX.23.1: Data 面板,选择Prope…...
78.子集--77.组合
78,子集 递归 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服务器与客户端的搭建
文章目录 🌲前言🌴ServerSocket API🎄Socket API🍀TCP中的长短连接🎍建立TCP回显客户端与服务器🚩TCP搭建服务器🚩TCP搭建客户端🚩通信过程展示: 🌳多个客户端…...

23111710[含文档+PPT+源码等]计算机毕业设计基于SpringBoot的体育馆场地预约赛事管理系统的设计
文章目录 **软件开发环境及开发工具:****功能介绍:****论文截图:****数据库:****实现:****代码片段:** 编程技术交流、源码分享、模板分享、网课教程 🐧裙:776871563 软件开发环境及…...

Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...

AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...