java agent-03-Java Instrumentation 结合 bytekit 实战笔记 agent attach

ops/2024/12/17 20:33:00/

java-agent-系列">java agent 系列

java agent 介绍

java agent-02-Java Instrumentation API

java agent-03-Java Instrumentation 结合 bytekit 实战笔记 agent attach

java agent-03-Java Instrumentation 结合 bytekit 实战笔记 agent premain

拓展阅读

前面几篇文档,我们简单介绍了一下 java Instrumentation。

java agent 介绍

Java Instrumentation API

本篇我们结合一下 bytekit 进行实际的文件修改。

测试代码

整体目录

    │  │  └─com│  │      └─github│  │          └─houbb│  │              └─bytekit│  │                  └─learn│  │                      └─agentattach│  │                          │  AgentAttachMain.java│  │                          │  MyAttachMain.java│  │                          │  MyClassFileTransformer.java│  │                          │  package-info.java│  │                          ││  │                          └─interceptor│  │                                  SampleInterceptor.java│  ││  └─resources│      └─META-INF│              MANIFEST.MF│└─test└─java└─com.github.houbb.bytekit.learn.agentattachSample.javaTestMain.java

MANIFEST.MF

Manifest-Version: 1.0
Agent-Class: com.github.houbb.bytekit.learn.agentattach.AgentAttachMain
Can-Redefine-Classes: true
Can-Retransform-Classes: true

AgentAttachMain-核心入口

这里指定了核心入口 AgentAttachMain

  • AgentAttachMain.java

动态 Attach 的 agent 与通过 JVM 启动 javaagent 参数指定的 agent jar 包的方式有所不同,动态 Attach 的 agent 会执行 agentmain 方法,而不是 premain 方法。

java">package com.github.houbb.bytekit.learn.agentattach;import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;public class AgentAttachMain {/*** 动态 Attach 的 agent 会执行 agentmain 方法,而不是 premain 方法。** @param agentArgs* @param inst* @throws ClassNotFoundException* @throws UnmodifiableClassException*/public static void agentmain(String agentArgs, Instrumentation inst) throws ClassNotFoundException, UnmodifiableClassException {System.out.println("agentmain called");Class classes[] = inst.getAllLoadedClasses();for (int i = 0; i < classes.length; i++) {String className = classes[i].getName();System.out.println(className);// 这里是正常的全称if (className.equals("com.github.houbb.bytekit.learn.agentattach.Sample")) {System.out.println("Reloading start: " + className);// 真实的替换final ClassFileTransformer transformer = new MyClassFileTransformer();inst.addTransformer(transformer, true);inst.retransformClasses(classes[i]);inst.removeTransformer(transformer);System.out.println("Reloading done: " + className);break;}}}}

MyClassFileTransformer 和上一篇类似,这里不过使用 bytekit 时要区分一下 install 的方式,或者会卡主。

此处不再赘述。

attach-main

创建MyAttachMain类,实现attach到目标进程 (为了方便我还是放在agent项目中)

因为是跨进程通信,Attach 的发起端是一个独立的 java 程序,这个 java 程序会调用 VirtualMachine.attach 方法开始和目标 JVM 进行跨进程通信。

下面的PID通过jps查看对应的进程ID,如11901

jarPath 为当前 agent 的完整包路径。

java">package com.github.houbb.bytekit.learn.agentattach;import com.github.houbb.bytekit.tool.utils.AttachHelper;
import com.sun.tools.attach.VirtualMachine;public class MyAttachMain {/*** 指定 pid 进行 attch** @param args* @throws Exception*/public static void main(String[] args) throws Exception {String pid = "15708";String jarPath = "D:\\github\\bytekit-learn\\bytekit-learn-agentattach\\target\\bytekit-learn-agentattach-1.0-SNAPSHOT.jar";AttachHelper.attach(jarPath, pid);// 通过 jps 查看VirtualMachine vm = VirtualMachine.attach(pid);try {vm.loadAgent(jarPath);} finally {vm.detach();}}}

测试

启动测试类

为了演示 attach,我们提供一个一直循环的测试类:

java">public class TestMain {public static void main(String[] args) throws InterruptedException {while (true) {Sample sample = new Sample();String result = sample.hello("123", false);System.out.println(result);TimeUnit.SECONDS.sleep(3);}}}

首先启动测试类。通过 jps 获取对应的信息

14028 RemoteMavenServer36
15100 Launcher
15708 TestMain

编译 agent

通过 mvn clean install 编译我们的 agent 包,生成在路径:

D:\\github\\bytekit-learn\\bytekit-learn-agentattach\\target\\bytekit-learn-agentattach-1.0-SNAPSHOT.jar

修改 attach-main 并启动

直接把 MyAttachMain 的 pid + agent 路径修改为对应的。启动测试:

对应的日志如下,实现已经被替换了

com.github.houbb.bytekit.learn.agentattach.Sample
Reloading start: com.github.houbb.bytekit.learn.agentattach.Sample
start transform name=== com/github/houbb/bytekit/learn/agentattach/Sample
/** Decompiled with CFR.*/
package com.github.houbb.bytekit.learn.agentattach;public class Sample {private int exceptionCount = 0;/** WARNING - void declaration*/public String hello(String string, boolean bl) {try {String string2;void str;void exception;try {String string3 = "(Ljava/lang/String;Z)Ljava/lang/String;";String string4 = "hello";Object[] objectArray = new Object[]{string, new Boolean(bl)};Class<Sample> clazz = Sample.class;Sample sample = this;System.out.println("atEnter, args[0]: " + objectArray[0]);}catch (RuntimeException runtimeException) {Class<Sample> clazz = Sample.class;RuntimeException runtimeException2 = runtimeException;System.out.println("exception handler: " + clazz);runtimeException2.printStackTrace();}if (exception != false) {++this.exceptionCount;throw new RuntimeException("test exception, str: " + (String)str);}String string5 = string2 = "hello " + (String)str;System.out.println("atExit, returnObject: " + string5);return string2;}catch (RuntimeException runtimeException) {int n = this.exceptionCount;RuntimeException runtimeException3 = runtimeException;System.out.println("atExceptionExit, ex: " + runtimeException3.getMessage() + ", field exceptionCount: " + n);throw runtimeException;}}
}end transform name=== com/github/houbb/bytekit/learn/agentattach/Sample
Reloading done: com.github.houbb.bytekit.learn.agentattach.Sample
atEnter, args[0]: 123
atExit, returnObject: hello 123
hello 123
atEnter, args[0]: 123
atExit, returnObject: hello 123
hello 123
atEnter, args[0]: 123
atExit, returnObject: hello 123
hello 123
atEnter, args[0]: 123
atExit, returnObject: hello 123
hello 123

拓展阅读

VirtualMachine 类不存在

添加jdk tools.jar解决com.sun.tools.attach.VirtualMachine 类找不到的问题

发现配置了 java_home 及相关信息还是不行,可以手动在项目中引入。

idea 就是 libs 种添加依赖。

参考资料

https://blog.51cto.com/zhangxueliang/5667216

https://www.cnblogs.com/756623607-zhang/p/12575509.html


http://www.ppmy.cn/ops/142726.html

相关文章

[element-ui] e-image 和e-table一起使用显示问题

使用element-plus组件库开发时&#xff0c;在el-table中嵌入el-image&#xff0c;图片预览时两者层叠&#xff0c;样式错乱。 // 单元格样式 .el-table__cell {position: static !important; // 解决el-image 和 el-table冲突层级冲突问题 }参考&#xff1a; element ui e-imag…

DataEase 开源 BI 工具 v2.10.3 LTS 发布

DataEase 开源 BI 工具 v2.10.3 LTS 发布 2024 年 12 月 9 日&#xff0c;开源 BI 工具 DataEase 正式发布 v2.10.3 LTS 版本。 此次更新带来了多方面的功能变化&#xff1a; 数据源&#xff1a;API 数据源与 Excel 数据源可设定字段类型与长度&#xff0c;优化数据接入的精准…

探索视觉与语言模型的可扩展性

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

3D相框案例讲解(详细)

前言 通过现阶段的学习&#xff0c;我们已经掌握了HTML&#xff0c;CSS和JS部分的相关知识点&#xff0c;现在让我们通过一篇案例&#xff0c;来巩固我们近期所学的知识点。 详细视频讲解戳这里 任务一 了解目标案例样式 1.1了解案例 3D相框 1.2 分析案例 首先我们看到一个…

Vue中纯前端实现导出简单Excel表格的功能

Vue 前端Excel导出 Vue中纯前端导出简单Excel表格的方法(使用vue-json-excel插件) 前言 在许多的后台系统中少不了导出Excel表格的功能&#xff0c;在项目中纯前端使用vue-json-excel插件来实现简单Excel表格的导出功能。 使用方法 1、安装依赖 npm install vue-json-exc…

Python大数据可视化:基于Python的王者荣耀战队的数据分析系统设计与实现_flask+hadoop+spider

开发语言&#xff1a;Python框架&#xff1a;flaskPython版本&#xff1a;python3.7.7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;PyCharm 系统展示 管理员登录 管理员功能界面 比赛信息管理 看板展示 系统管理 摘要 本文使用Python与…

【AI图像生成网站Golang】项目架构

AI图像生成网站 目录 一、项目介绍 二、雪花算法 三、JWT认证与令牌桶算法 四、项目架构 五、图床上传与图像生成API搭建 六、项目测试与调试(等待更新) 四、项目架构 本项目的后端基于Golang和Gin框架开发&#xff0c;主要包括的模块有&#xff1a; backend/ ├── …

Apache Seatunnel Web 使用指南

Apache Seatunnel Web 使用指南 项目地址:https://gitcode.com/gh_mirrors/sea/seatunnel-web 项目介绍 Apache Seatunnel Web 是一个强大的数据集成平台&#xff0c;旨在简化数据管道的构建和管理过程。它基于著名的 Apache Seatunnel&#xff08;原名 Flatten&#xff09;…