从利用Arthas排查线上Fastjson问题到Java动态字节码技术(下)
上一篇从Arthas的源码引出了Java动态字节码技术,那么这一篇就从几种Java字节码技术出发,看看Arthas是如何通过动态字节码技术做到无侵入的源码增强;
Java大部分情况下都是解释执行的,也就是解释.class文件,所以如果我们想对原代码进行增强的话,直接接的手段便是从源文件.java入手,使用静态代理、动态代理、装饰器等设计模式进行功能增强。但很多时候我们作为第三方,没有机会、不方便拿到源码时,这条路就走不通了;此时如果还是想继续其进行功能增强的话,那么只剩一条路了,就是直接对.class文件下手。
但对于二进制的.class文件,还有多少人能分清魔数、标识符、各种区域表示的内容呢?所以直接操作字节码也似乎不太现实,那有没有什么抓手呢?
ASM
ASM 是 assembly 汇编 的简称,所以它更偏底层、更贴近底层字节码,所以也就更难使用、更晦涩。
整体思路上是通过Reader将.class文件读取后,通过一系列API来增强源码,之后通过Writer生成新的.class文件。
个人不太建议使用这种方式,学习和使用成本都比较高,不直观,太晦涩。
Javaassist
相比于ASM,理解起来不要太简单,不需要了解底层虚拟机指令和晦涩的API,只需要掌握四个核心类即可 ClassPool、CtClass、CtMethod、CtField:
CtClass(compile-time class):编译时 - 类对象,Java中万物皆对象,CtClass是Class在编译时的对象,可以通过类的全限定名来获取到这个CtClass;
与编译时(compile)类对象相似的,我们平时用反射获取到的是运行时(Runtime)类对象;
ClassPool:可以把它简单的理解为一个HashMap,类的全限定名作为key,可以从中获取到CtClass
CtMethod & CtField:类中的方法和属性
利用以上四个类,可以快速实现对源码的增强,比如当你想实现AOP,在原方法执行前和执行后添加功能的时候,只需要先通过ClassPool获取到CtClass,再获取到CtMethod后,就可以调用该方法的insertBefore和insertAfter,插入具体代码块了。
Instrument
Instrument是JVM提供的一个对已加载的类进行修改的接口(Interface),打开java.lang.Instrumentation可以看到清晰的说明。
首先Instrument是基于 Java Agent技术的,也就是上一篇中提到的,用 agentmain 和 premain attache java进程生成的 agent,也就是为 Instrument 在运行的进程中开了一个后门。
在instrument接口中最重要的方法是 通过ClassFileTransformer 对原class进行 retransform;
在ClassFileTransformer中实现想要对原class的增强,该接口只有一个需要被子类实现的方法,就是transform方法:
package java.lang.instrument;public interface ClassFileTransformer {byte[]transform( ClassLoader loader,String className,Class<?> classBeingRedefined,ProtectionDomain protectionDomain,byte[] classfileBuffer)throws IllegalClassFormatException;
}
举一个直观的例子,福报厂的ttl threadpool:
package com.alibaba.ttl.threadpool.agent;public class TtlTransformer implements ClassFileTransformer {//类似于责任链,可以添加一系列的 ClassFileTransformer//值得注意的是,这里使用到了Javassistprivate final List<JavassistTransformlet> transformletList = new ArrayList<JavassistTransformlet>();TtlTransformer(List<? extends JavassistTransformlet> transformletList) {for (JavassistTransformlet transformlet : transformletList) {this.transformletList.add(transformlet);logger.info("[TtlTransformer] add Transformlet " + transformlet.getClass() + " success");}}@Overridepublic final byte[] transform(@Nullable final ClassLoader loader, @Nullable final String classFile, final Class<?> classBeingRedefined,final ProtectionDomain protectionDomain, @NonNull final byte[] classFileBuffer) {final String className = toClassName(classFile);//通过classloader和classname加载了原class对象ClassInfo classInfo = new ClassInfo(className, classFileBuffer, loader);//对原class对象,依次应用 ClassFileTransformer,并返回transform后的新class对象for (JavassistTransformlet transformlet : transformletList) {transformlet.doTransform(classInfo);if (classInfo.isModified()) return classInfo.getCtClass().toBytecode();}}
}
这时就可以回到上一篇中Arthas的核心启动类ArthasBootstrap ==> transformerManager = new TransformerManager(instrumentation);
在TransformerManager中,有三类增强功能:watcher/tarce/其余的归为reTransformers
public TransformerManager(Instrumentation instrumentation) {this.instrumentation = instrumentation;classFileTransformer = new ClassFileTransformer() {@Overridepublic byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {for (ClassFileTransformer classFileTransformer : reTransformers) {byte[] transformResult = classFileTransformer.transform(loader, className, classBeingRedefined,protectionDomain, classfileBuffer);if (transformResult != null) {classfileBuffer = transformResult;}}for (ClassFileTransformer classFileTransformer : watchTransformers) {byte[] transformResult = classFileTransformer.transform(loader, className, classBeingRedefined,protectionDomain, classfileBuffer);if (transformResult != null) {classfileBuffer = transformResult;}}for (ClassFileTransformer classFileTransformer : traceTransformers) {byte[] transformResult = classFileTransformer.transform(loader, className, classBeingRedefined,protectionDomain, classfileBuffer);if (transformResult != null) {classfileBuffer = transformResult;}}return classfileBuffer;}};instrumentation.addTransformer(classFileTransformer, true);
}
以其中的Watcher为例子,看下Arthas底层是如何增强源码的;
//继承java.lang.instrument包中的 ClassFileTransformer 接口
public class Enhancer implements ClassFileTransformer {@Overridepublic byte[] transform(final ClassLoader inClassLoader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {//底层是ASMClassNode classNode = new ClassNode(Opcodes.ASM9);//首先获取原class对象ClassReader classReader = AsmUtils.toClassNode(classfileBuffer, classNode);classNode = AsmUtils.removeJSRInstructions(classNode);List<MethodNode> matchedMethods = new ArrayList<MethodNode>();for (MethodNode methodNode : classNode.methods) {if (!isIgnore(methodNode, methodNameMatcher)) {matchedMethods.add(methodNode);}}for (MethodNode methodNode : matchedMethods) {if (AsmUtils.isNative(methodNode)) {continue; //过滤调native方法}if(AsmUtils.containsMethodInsnNode(methodNode, Type.getInternalName(SpyAPI.class), "atBeforeInvoke")) {... //对class的方法添加watch功能}}return AsmUtils.toBytes(classNode, inClassLoader, classReader); //返回新的class对象}
}
相关文章:
从利用Arthas排查线上Fastjson问题到Java动态字节码技术(下)
上一篇从Arthas的源码引出了Java动态字节码技术,那么这一篇就从几种Java字节码技术出发,看看Arthas是如何通过动态字节码技术做到无侵入的源码增强; Java大部分情况下都是解释执行的,也就是解释.class文件,所以如果我们…...
Ubuntu中安装Anaconda 如何将 路径导入为全局变量
第一步:将你的anaconda 路径复制下来,在终端输入对应路径。 echo export PATH"/home/你的用户名/anaconda3/bin:$PATH" >> ~/.bashrc 第二步:在终端输入下面命令或者重启系统。 source ~/.bashrc 在对应的anaconda安装目…...
【QT】Qt的随身笔记(持续更新...)
目录 Qt 获取当前电脑桌面的路径Qt 获取当前程序运行路径Qt 创建新的文本文件txt,并写入内容如何向QPlainTextEdit 写入内容QTimerQMessageBox的使用QLatin1StringQLayoutC在c头文件中写#include类的头文件与直接写class加类名有何区别mutable关键字前向声明 QFontQ…...
【LeetCode-简单题】589. N 叉树的前序遍历
文章目录 题目方法一:单循环栈做法方法二:递归 题目 方法一:单循环栈做法 关键在于子节点的入栈顺序,决定了子节点的出栈顺序, 因为是前序遍历 所以压栈顺序先让右边的入栈 依次往左 这样左边的节点会在栈顶 这样下次…...
Linphone3.5.2 ARM RV1109音视频对讲开发记录
Linphone3.5.2 ARM RV1109音视频对讲开发记录 说明 这是一份事后记录,主要记录的几个核心关键点,有可能很多细节没有记上,主要是方便后面自己再找回来! 版本 3.5.2 一些原因选的是这样一个旧的版本! 新的开发最好选新一些的版…...
Unity用相机实现的镜子效果
首先登场 场景中的元素 mirror是镜子,挂着我们的脚本,Quad是一个面片。Camera是用来生成RenderTexture给面片的。里面的test1是我用来调试位置的球。 镜子size是大小,x是-2,为了反转一下贴图 相机直接可以禁用掉,用…...
计算机网络分类
按照覆盖范围分类 (1)个域网:通常覆盖范围在1~10m。 (2)局域网:通常覆盖范围在10m~1km。 (3)城域网:覆盖范围通常在5~50 km 。 &…...
AI AIgents时代 - (三.) AutoGPT和AgentGPT
前两篇讲解了Agent的原理和组件,这节我将给大家介绍两个agent项目,给出它们的工作原理和区别,并教大家亲手尝试使用 Agents🎉 🟢 AutoGPT🤖️ 我们的老朋友,之前文章也专门写过。AutoGPT 是一…...
Jmeter接口自动化和Python接口自动化,如何选择?
选择Jmeter或Python进行接口自动化测试取决于您的具体需求和环境。以下是一些可以考虑的因素: 1. 语言熟悉度:如果您对Java更熟悉,那么Jmeter可能是更好的选择。而如果您的团队或个人对Python更熟悉,那么Python可能是更好的选择。…...
Sqilte3初步教程
文章目录 安装创建数据库创建和删除表插入行数据 安装 Windows下安装,首先到下载页面,下载Windows安装软件,一般是 sqlite-dll-win32-*.zip sqlite-tools-win32-*.zip下载之后将其内容解压到同一个文件夹下,我把它们都放在了D:\…...
详解Python中的json库
目录 1. json简介2. dumps/loads3. dump/load4. jsonl格式 1. json简介 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,用于在不同应用程序之间传递数据。它是一种文本格式,易于阅读和编写,同时也易于…...
【Spring Boot】Spring Boot源码解读与原理剖析
这里写目录标题 前言精进Spring Boot首选读物“小册”变“大书”,彻底弄懂Spring Boot全方位配套资源,学不会来找我!技术新赛道,2023领先抢跑 前言 承载着作者的厚望,掘金爆火小册同名读物《Spring Boot源码解读与原理…...
C++学习(1)
一、C概述(了解) C在C语言的基础上添加了面向对象编程和泛型编程的支持 二、helloword程序(掌握) #define _CET_SECURE_NO_WARNINGS//在开发软件visual studio编译 c文件时, visual studio认为strcpy,scanf等函数不安全的导致报…...
机器人如何有效采摘苹果?
摘要:本文利用动捕数据构建拟人运动模型,对比观察两种苹果采摘模式,并对系统性能进行全面评估,为提高机器人采摘效率提供创新方法。 近期,一项关于苹果采摘机器人的有趣研究—— "Design and evaluation of a rob…...
C# OpenCvSharp Yolov8 Detect 目标检测
效果 项目 代码 using OpenCvSharp; using OpenCvSharp.Dnn; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms;namespace Open…...
rust数组
一、定义数组 (一)一维数组 1.指定所有元素 语法格式 let variable_name: [dataType; size] [value1,value2,value3];例如 let arr: [i32; 4] [10,20,30,40];2.指定初始值和长度 所有元素具有相同的值 语法格式 let variable_name: [dataType; siz…...
ubuntu | 安装NVIDIA套件:驱动、CUDA、cuDNN
CUDA 查看支持最高的cuda版本 nvidia-smiCUDA Version:12.2 区官网下在12.2.x最新的版本即可CUDA Toolkit Archive | NVIDIA Developer 下载安装 wget https://developer.download.nvidia.com/compute/cuda/12.2.2/local_installers/cuda_12.2.2_535.104.05_linux.run sudo…...
JAVA学习笔记
一、学习要点 java的最大优势就是跨平台; java的三个版本,javaSE标准版本,javaEE企业版本,javaME微型版本(用的比较少); JVM(Java Virtual Machine,Java虚拟机); JRE…...
车载软件架构 —— 持续集成持续交付
车载软件架构 —— 持续集成持续交付 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 对学习而言,学习之后的思考、思考之后的行动、行动之后的改变更重要,如果不盯住内层的改变量,那么在表层投…...
c++ 二元运算符重载, 以加法为例
/* * c 二元运算符重载, 以加法为例 */ #include <stdio.h> class Complex { public: int r0; // real, 实部 int v0; //virtual, 虚部 }; // 重载加法 操作符 // 可见,c2元运算符,取其左侧为第一参数,右侧为第二参数 // 返回值可以付给新的变量 C…...
大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...
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方式进行封装,供调用如何按…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...
STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...
