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

Skywalking流程分析_5(字节码增强)

SkyWalkingAgent.Transformer#transform

此方法就是进行字节码增强的过程

private static class Transformer implements AgentBuilder.Transformer {private PluginFinder pluginFinder;Transformer(PluginFinder pluginFinder) {this.pluginFinder = pluginFinder;}@Overridepublic DynamicType.Builder<?> transform(//当前拦截到的类的字节码final DynamicType.Builder<?> builder,//可以理解成class 包括类的描述信息                                final TypeDescription typeDescription,//当前拦截到的类的类加载器final ClassLoader classLoader,final JavaModule javaModule,final ProtectionDomain protectionDomain) {//如果当前拦截的类的类加载器是URLClassLoader类型,则进行收集LoadedLibraryCollector.registerURLClassLoader(classLoader);//找到对此类匹配的所有插件List<AbstractClassEnhancePluginDefine> pluginDefines = pluginFinder.find(typeDescription);if (pluginDefines.size() > 0) {DynamicType.Builder<?> newBuilder = builder;//增强上下文EnhanceContext context = new EnhanceContext();for (AbstractClassEnhancePluginDefine define : pluginDefines) {//调用每个插件的define()方法去做字节码增强DynamicType.Builder<?> possibleNewBuilder = define.define(typeDescription, newBuilder, classLoader, context);if (possibleNewBuilder != null) {newBuilder = possibleNewBuilder;}}if (context.isEnhanced()) {LOGGER.debug("Finish the prepare stage for {}.", typeDescription.getName());}//被所有匹配的插件修改完后最终字节码return newBuilder;}LOGGER.debug("Matched class {}, but ignore by finding mechanism.", typeDescription.getTypeName());//原始字节码return builder;}
}

总结:

  • 找到对此类匹配的所有插件
  • 如果找到有匹配上的插件,调用每个插件的define()方法去做字节码增强,然后增强后的字节码
  • 如果没有找到匹配的插件,则返回原始字节码

找到对此类匹配的所有插件

pluginFinder.find(typeDescription)

public class PluginFinder {/*** Map的泛型为<String,List>的原因是对于同一个类,可能会有多个插件都要对这个类进行字节码增加* * key -> 目标类* value -> 所有可以对这个目标类生效的插件* */private final Map<String, LinkedList<AbstractClassEnhancePluginDefine>> nameMatchDefine = new HashMap<String, LinkedList<AbstractClassEnhancePluginDefine>>();private final List<AbstractClassEnhancePluginDefine> signatureMatchDefine = new ArrayList<AbstractClassEnhancePluginDefine>();private final List<AbstractClassEnhancePluginDefine> bootstrapClassMatchDefine = new ArrayList<AbstractClassEnhancePluginDefine>();private static boolean IS_PLUGIN_INIT_COMPLETED = false;/**** 得到对指定类型生效的所有匹配插件,包括命名查找、间接匹配查找*/public List<AbstractClassEnhancePluginDefine> find(TypeDescription typeDescription) {List<AbstractClassEnhancePluginDefine> matchedPlugins = new LinkedList<AbstractClassEnhancePluginDefine>();String typeName = typeDescription.getTypeName();if (nameMatchDefine.containsKey(typeName)) {matchedPlugins.addAll(nameMatchDefine.get(typeName));}for (AbstractClassEnhancePluginDefine pluginDefine : signatureMatchDefine) {IndirectMatch match = (IndirectMatch) pluginDefine.enhanceClass();if (match.isMatch(typeDescription)) {matchedPlugins.add(pluginDefine);}}return matchedPlugins;}}

EnhanceContext context = new EnhanceContext()

此类的作用是用作是否增强的标识

/*** The <code>EnhanceContext</code> represents the context or status for processing a class.* <p>* Based on this context, the plugin core {@link ClassEnhancePluginDefine} knows how to process the specific steps for* every particular plugin.* * 此类的作用是记录当前被拦截的类是否被修改了字节码和是否新增了新的字段或接口*/
public class EnhanceContext {private boolean isEnhanced = false;/*** The object has already been enhanced or extended. e.g. added the new field, or implemented the new interface*/private boolean objectExtended = false;public boolean isEnhanced() {return isEnhanced;}public void initializationStageCompleted() {isEnhanced = true;}public boolean isObjectExtended() {return objectExtended;}public void extendObjectCompleted() {objectExtended = true;}
}

字节码增强

define.define(typeDescription, newBuilder, classLoader, context)

这里调用的其实就调用了插件的顶级接口AbstractClassEnhancePluginDefine的方法

public DynamicType.Builder<?> define(TypeDescription typeDescription, DynamicType.Builder<?> builder,ClassLoader classLoader, EnhanceContext context) throws PluginException {// 当前的插件的全类名String interceptorDefineClassName = this.getClass().getName();// 当前要被增加的类全类名String transformClassName = typeDescription.getTypeName();if (StringUtil.isEmpty(transformClassName)) {LOGGER.warn("classname of being intercepted is not defined by {}.", interceptorDefineClassName);return null;}LOGGER.debug("prepare to enhance class {} by {}.", transformClassName, interceptorDefineClassName);WitnessFinder finder = WitnessFinder.INSTANCE;/*** find witness classes for enhance class*///版本查找//通过类识别String[] witnessClasses = witnessClasses();if (witnessClasses != null) {for (String witnessClass : witnessClasses) {//判断类加载器中存不存在这个标识类if (!finder.exist(witnessClass, classLoader)) {LOGGER.warn("enhance class {} by plugin {} is not activated. Witness class {} does not exist.", transformClassName, interceptorDefineClassName, witnessClass);return null;}}}//通过方法识别(和通过类识别的逻辑相同)List<WitnessMethod> witnessMethods = witnessMethods();if (!CollectionUtil.isEmpty(witnessMethods)) {for (WitnessMethod witnessMethod : witnessMethods) {if (!finder.exist(witnessMethod, classLoader)) {LOGGER.warn("enhance class {} by plugin {} is not activated. Witness method {} does not exist.", transformClassName, interceptorDefineClassName, witnessMethod);return null;}}}/*** find origin class source code for interceptor* 进行真正的字节码增强修改*/DynamicType.Builder<?> newClassBuilder = this.enhance(typeDescription, builder, classLoader, context);//将isEnhanced的标识位设置为truecontext.initializationStageCompleted();LOGGER.debug("enhance class {} by {} completely.", transformClassName, interceptorDefineClassName);return newClassBuilder;
}

总结

  • witnessClasses()和witnessMethods()检查插件是否生效,在之前的文章详细分析过
  • enhance方法进行字节码增强
  • 将EnhanceContext标识设置为已增强
版本识别的具体判断插件是否生效

witnessClasses()和witnessMethods()返回的类和方法都是要调用finder.exist来判断当前应用是否存在

public enum WitnessFinder {INSTANCE;/*** TypePool为类加载器的所有能加载的类型* */private final Map<ClassLoader, TypePool> poolMap = new HashMap<ClassLoader, TypePool>();/*** @param classLoader for finding the witnessClass* @return true, if the given witnessClass exists, through the given classLoader.*/public boolean exist(String witnessClass, ClassLoader classLoader) {return getResolution(witnessClass, classLoader).isResolved();}private TypePool.Resolution getResolution(String witnessClass, ClassLoader classLoader) {ClassLoader mappingKey = classLoader == null ? NullClassLoader.INSTANCE : classLoader;if (!poolMap.containsKey(mappingKey)) {synchronized (poolMap) {if (!poolMap.containsKey(mappingKey)) {TypePool classTypePool = classLoader == null ? TypePool.Default.ofBootLoader() : TypePool.Default.of(classLoader);poolMap.put(mappingKey, classTypePool);}}}TypePool typePool = poolMap.get(mappingKey);//从这个类型池中查找这个类存不存在return typePool.describe(witnessClass);}public boolean exist(WitnessMethod witnessMethod, ClassLoader classLoader) {//方法所在的类是否在这个ClassLoader中TypePool.Resolution resolution = getResolution(witnessMethod.getDeclaringClassName(), classLoader);if (!resolution.isResolved()) {return false;}//判断该方法是否存在return !resolution.resolve().getDeclaredMethods().filter(witnessMethod.getElementMatcher()).isEmpty();}}final class NullClassLoader extends ClassLoader {static NullClassLoader INSTANCE = new NullClassLoader();
}
  • witnessClass(),会基于传入的classLoader构造TypePool来判断witnessClass是否存在,TypePool最终会存储到Map中
  • witnessMethod(),先判断此方法所在的类是否在这个ClassLoader中,也就是先执行witnessClass(),再判断该方法是否存在
真正的字节码增强

this.enhance(typeDescription, builder, classLoader, context)

protected DynamicType.Builder<?> enhance(TypeDescription typeDescription, DynamicType.Builder<?> newClassBuilder,ClassLoader classLoader, EnhanceContext context) throws PluginException {//静态方法的增强newClassBuilder = this.enhanceClass(typeDescription, newClassBuilder, classLoader);//构造、实例方法的增强newClassBuilder = this.enhanceInstance(typeDescription, newClassBuilder, classLoader, context);return newClassBuilder;
}

下一篇会详细介绍真正字节码增强的流程

相关文章:

Skywalking流程分析_5(字节码增强)

SkyWalkingAgent.Transformer#transform 此方法就是进行字节码增强的过程 private static class Transformer implements AgentBuilder.Transformer {private PluginFinder pluginFinder;Transformer(PluginFinder pluginFinder) {this.pluginFinder pluginFinder;}Override…...

Windows conan环境搭建

Windows conan环境搭建 1 安装conan1.1 安装依赖软件1.1.1 python安装1.1.2 git bash安装1.1.3 安装Visual Studio Community 20191.1.3.1 选择安装的组件1.1.3.2 选择要支持的工具以及对应的SDK 1.1.4 vscode安装 1.3 验证conan功能1.4 查看conancenter是否包含poco包1.5 查看…...

如何使用Cpolar+Tipask,在ubuntu系统上搭建一个私人问答网站

文章目录 前言2.Tipask网站搭建2.1 Tipask网站下载和安装2.2 Tipask网页测试2.3 cpolar的安装和注册 3. 本地网页发布3.1 Cpolar临时数据隧道3.2 Cpolar稳定隧道&#xff08;云端设置&#xff09;3.3 Cpolar稳定隧道&#xff08;本地设置&#xff09; 4. 公网访问测试5. 结语 前…...

怎么在uni-app中使用Vuex(第一篇)

Vuex简介 vuex的官方网址如下 https://vuex.vuejs.org/zh/ 阅读官网请带着几个问题去阅读&#xff1a; vuex用于什么场景&#xff1f;vuex能给我们带来什么好处&#xff1f;我们为什么要用vuex?vuex如何实现状态集中管理&#xff1f; Vuex用于哪些场景&#xff1f; 组件之…...

【MySQL】库的相关操作 + 库的备份和还原

库的操作 前言正式开始创建数据库删除数据库编码集查看系统默认字符集以及校验规则字符集校验规则 所有支持的字符集和校验规则所有字符集所有校验规则 指明字符集和校验规则创建数据库相同的字符集用不同的校验规则读取会出现什么情况 alter修改数据库show create databasealt…...

网络安全基础之php开发文件上传的实现

前言 php是网络安全学习里必不可少的一环&#xff0c;简单理解php的开发环节能更好的帮助我们去学习php以及其他语言的web漏洞原理 正文 在正常的开发中&#xff0c;文件的功能是必不可少&#xff0c;比如我们在论坛的头像想更改时就涉及到文件的上传等等文件功能。但也会出…...

[文件读取]cuberite 文件读取 (CVE-2019-15516)

1.1漏洞描述 漏洞编号CVE-2019-15516漏洞类型文件上传漏洞等级⭐⭐⭐漏洞环境VULFOCUS攻击方式 描述: Cuberite是一款使用C语言编写的、轻量级、可扩展的多人游戏服务器。 Cuberite 2019-06-11之前版本中存在路径遍历漏洞。该漏洞源于网络系统或产品未能正确地过滤资源或文件路…...

SpringBoot 自定义参数校验(5)

文章目录 前言方式一 @Pattern方式二 自定义参数校验Controller层请求示例前言 本文基于SpringBoot 3.1.2,使用自定义参数规则来处理参数校验。 方式一 @Pattern 使用@Pattern,自定义正则表达式,以下是一个校验IP地址的示例: import jakarta.validation.constraints.Not…...

Win Docker Desktop + WSL2 部署PyTorch-CUDA服务至k8s算力集群

Win Docker Desktop WSL2 部署PyTorch-CUDA服务至k8s算力集群 Win Docker Desktop WSL2 安装安装WSL-Ubuntu拉取镜像并测试挂载数据并开放端口导出镜像或导入镜像在k8s集群部署 Win Docker Desktop WSL2 安装 首先根据你的操作系统版本 安装WSL &#xff0c;记得切换WSL2&a…...

JLMR Micro Super Resolution Algorithm国产微超分算法DEMO

一、简介 目前&#xff0c;做超分算法基本还是以AI训练为主&#xff0c;但是AI基本上都是基于既定场景的训练。而传统的算法基本上都是利用上下文的纹理预测、插值等方案&#xff0c;在图像放大过程中会出现模糊&#xff0c;或马赛克等现象。 我们基于加权概率模型&#xff0c…...

Docker的安装配置与使用

1、docker安装与启动 首先你要保证虚拟机所在的盘要有至少20G的空间&#xff0c;因为docker开容器很吃空间的&#xff0c;其次是已经安装了yum依赖 yum install -y epel-release yum install docker-io # 安装docker配置文件 /etc/sysconfig/docker chkconfig docker on # 加…...

macOS文本编辑器 BBEdit 最新 for mac

BBEdit是一款功能强大的文本编辑器&#xff0c;适用于Mac操作系统。它由Bare Bones Software开发&#xff0c;旨在为开发者和写作人员提供专业级的文本编辑工具。 以下是BBEdit的一些主要特点和功能&#xff1a; 多语言支持&#xff1a;BBEdit支持多种编程语言和标记语言&…...

Android Audio实战——音量设置Hal(二十)

本来上一篇分析音量设置中对于 setCurrentGainIndex 方法我们分析到了 native 层就没有往下分析,但这这里还有准备再看看下面的流程。 一、源码分析 1、android_media_AudioSystem.cpp 源码位置:frameworks/base/core/jni/android_media_AudioSystem.cpp static jint and…...

jetson配置笔记

typora-root-url: /home/msj/ubuntu笔记本台式机环境配置说明/images Ubuntu18.04 配置 说明&#xff1a;我们所有文档配置都是按照ubuntu18.04&#xff0c;保证x86架构(笔记本台式机)和 ARM架构(jetson Nano只能安装18.04)的一致性 1. 更换各类源 我们所有源都更换清华源&a…...

使用select实现定时任务

selectOutOfTime.c里边的代码如下&#xff1a; #include<stdio.h> #include<sys/time.h> #include<sys/types.h> #include<unistd.h> #include <string.h>#define BUF_SIZE 100int main(void){fd_set reads;struct timeval tv;int errorNum;cha…...

uniapp的实战总结大全

&#x1f642;博主&#xff1a;冰海恋雨 &#x1f642;文章核心&#xff1a;uniapp部分总结 目录 ​编辑 目录 前言&#xff1a; 解决方案 1. 跨平台开发 2. Vue.js生态 3. 组件库 4. 自定义组件 5. Native能力 6. 插件生态 7. 性能优化 写法 1. 模板&#xf…...

No205.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…...

保序回归:拯救你的校准曲线(APP)

保序回归&#xff1a;拯救你的校准曲线&#xff08;APP&#xff09; 校准曲线之所以是评价模型效能的重要指标是因为&#xff0c;校准曲线衡量模型预测概率与实际发生概率之间的一致性&#xff0c;它可以帮助我们了解模型的预测结果是否可信。一个理想的模型应该能够准确地预测…...

清华镜像源地址,适用于pip下载速度过慢从而导致下载失败的问题

清华地址 https://pypi.tuna.tsinghua.edu.cn/simple下载各种各样的包的指令模板 pip install XXX -i https://pypi.tuna.tsinghua.edu.cn/simple这样就行了&#xff0c;XXX代表的是你将要下载的包名称。 比如&#xff1a; pip install opencv-python -i https://pypi.tuna.…...

arcgis--NoData数据处理

方法一&#xff1a;利用【栅格计算器】可以对NoData的值进行修改。【Spatial Analyst工具】-【地图代数】-【栅格计算器】&#xff0c;将NoData修改为某一个值。 方法二&#xff1a;先对原始数据进行重分类&#xff0c;分成1类&#xff0c;将NoData赋值为2,。然后&#xff0c;将…...

ESXi 8.0U3i在部署过程中出现技嘉(GIGABYTE)Z390 I AORUS PRO WIFI主板+万兆intel x520-da2 sr2 82599ES万兆网卡不识别处理方法

你遇到的问题核心是&#xff1a;ESXi 8.0U3i 原生 / 通用集成镜像缺少对技嘉 Z390 I AORUS PRO WIFI 板载网卡、Intel X520-DA2(82599ES)万兆网卡及部分 NVMe/USB 控制器的完整驱动支持。解决思路是&#xff1a;先排查 BIOS → 再用定制镜像(下载现成或自己封装)→ 最后验证驱动…...

OpenClaw多通道控制:Qwen3-32B-Chat同时响应飞书与网页端指令

OpenClaw多通道控制&#xff1a;Qwen3-32B-Chat同时响应飞书与网页端指令 1. 为什么需要多通道控制&#xff1f; 上周三晚上11点&#xff0c;我正在用OpenClaw的网页控制台整理项目文档&#xff0c;突然飞书弹出同事的紧急需求&#xff1a;"能不能立刻帮我生成上季度销售…...

深入解析FOC控制中的Clark/Park变换及其Matplotlib动态仿真实现

1. 从三相交流电到FOC控制的基础认知 第一次接触电机控制时&#xff0c;看到那些复杂的坐标变换公式确实让人头疼。但后来我发现&#xff0c;理解FOC&#xff08;磁场定向控制&#xff09;的核心&#xff0c;关键在于抓住两个关键点&#xff1a;为什么要做坐标变换和变换后能解…...

Z-Image-Turbo镜像优化指南:如何调整参数获得更佳生成效果

Z-Image-Turbo镜像优化指南&#xff1a;如何调整参数获得更佳生成效果 1. 镜像核心参数解析 Z-Image-Turbo作为一款高性能文生图模型&#xff0c;其效果很大程度上取决于参数配置。理解这些参数的作用是优化生成效果的第一步。 1.1 基础参数说明 prompt&#xff08;提示词&…...

Keil“魔法棒”全解析:从Device到Utilities的配置秘籍

1. 认识Keil的"魔法棒"&#xff1a;Options for Target对话框 第一次打开Keil MDK时&#xff0c;工具栏上那个带着星星的魔法棒图标总是特别引人注目。这个被开发者亲切称为"魔法棒"的按钮&#xff0c;实际上是整个开发环境中最强大的配置中心——Options …...

用Matlab/Simulink手把手教你设计交错式升压DC-DC转换器(附PI参数整定代码)

从零构建交错式升压DC-DC转换器的MATLAB实战指南 交错式升压拓扑正在新能源领域掀起一场静默革命——当电动汽车的电池管理系统需要稳定升压时&#xff0c;当光伏逆变器要处理不稳定的直流输入时&#xff0c;这种能显著降低电流纹波的结构已成为工程师的秘密武器。但理论图纸与…...

轻量模型不轻量:Nano-Banana Turbo LoRA在A10显卡上30秒出图实测

轻量模型不轻量&#xff1a;Nano-Banana Turbo LoRA在A10显卡上30秒出图实测 1. 项目简介 Nano-Banana是一款专门为产品拆解和平铺展示风格设计的轻量化文生图系统。这个项目的核心在于深度融合了专属的Turbo LoRA微调权重&#xff0c;专门针对Knolling平铺、爆炸图、产品部件…...

Cesium实战:手把手教你实现智慧城市中的动态流动线(附完整代码与避坑指南)

Cesium实战&#xff1a;打造智慧城市动态流动线的完整技术方案 在数字孪生和智慧城市可视化项目中&#xff0c;动态流动线是实现交通流、管网流向等动态效果的关键元素。本文将深入探讨如何基于Cesium引擎&#xff0c;从Shader编写到前端集成&#xff0c;构建高性能的动态线可视…...

突破性Unity游戏插件框架实战指南:BepInEx从零到精通的完全手册

突破性Unity游戏插件框架实战指南&#xff1a;BepInEx从零到精通的完全手册 【免费下载链接】BepInEx Unity / XNA game patcher and plugin framework 项目地址: https://gitcode.com/GitHub_Trending/be/BepInEx BepInEx是一款专为Unity游戏设计的革命性插件框架&…...

Keil4 STC15浮点运算踩坑实录:如何避免数据类型转换导致的诡异错误

Keil4 STC15浮点运算避坑指南&#xff1a;从原理到实战的数据类型陷阱解析 在嵌入式开发领域&#xff0c;STC15系列单片机凭借其优异的性价比和丰富的功能接口&#xff0c;成为许多中小型项目的首选。然而当开发者使用Keil4这一经典但略显陈旧的开发环境时&#xff0c;常常会遇…...