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

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

【Linux】shell脚本忽略错误继续执行

在 shell 脚本中&#xff0c;可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行&#xff0c;可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令&#xff0c;并忽略错误 rm somefile…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

04-初识css

一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...