当前位置: 首页 > 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;将…...

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框&#xff0c;很难让人不联想到SQL注入&#xff0c;但提示都说了不是SQL注入&#xff0c;所以就不往这方面想了 ​ 先查看一下网页源码&#xff0c;发现一段JavaScript代码&#xff0c;有一个关键类ctfs…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

Java编程之桥接模式

定义 桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型设计模式&#xff0c;它的核心意图是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过组合关系来替代继承关系&#xff0c;从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...