非Attach方式
src\main\resources\META-INF\MANIFEST.MF
1 | Premain-Class: org.example.AgentMain |
pom
1 | <dependency> |
MyTest
1 | package org.example; |
AgentMain
1 | package org.example; |
MyMethodVisitor
1 | package org.example; |
MyClassVisitor
1 | package org.example; |
MyClassFileTransformer
1 | package org.example; |
启动
1 | java -javaagent:'D:\Projects\2022SEU\JVMBookTest\target\JVMBookTest-1.0-SNAPSHOT.jar' org.example.MyTest |
Attach方式(成功复现!)
- 《深入理解JVM字节码》7.3
Page180-183
- 参考
测试代码中的main方法,每3秒输出foo的返回值100。后面会Attach上MyTestMain,修改foo的字节码,让foo返回50
主要类
- MyTestMain
- AgentMain
- MyAttachMain
环境配置
- 添加依赖
attach的使用涉及com.sun.tools.attach
,因此需要在POM中引入本地tools包,否则会找不到tools。
tools包在JAVA_HOME,比如在我的设备中,其绝对位置为D:/Program Files/java/jdk1.8.0_261/lib/tools.jar
1 |
|
D:\Projects\2022SEU\my-javaagent\src\main\resources\META-INF\MANIFEST.MF
MF文件配置,注意最后一行有空行
1 | Manifest-Version: 1.0 |
AgentMain
代理类,包含了MethodVisitor、MyClassVisitor、MyClassFileTransformer以及agentmain(这里是动态配置,所以不用写入Premain类)
1 | package org.example; |
MyTestMain
1 | package org.example; |
MyAttachMain
1 | package org.example; |
启动方法
- 运行MyTestMain
- 在命令行中输入
1 | jps |
显示MyTestMain的PID
- 在MyAttachMain中填入PID
- 在命令行输入以下命令,生成jar包
1 | mvn clean package |
- 在MyAttachMain中loadAgent填入生成jar包的绝对位置
- 运行MyAttachMain(不需要-javaagent,直接run即可)
- 效果如图,从100变成50
通过Attach方式复现函数调用链Lab
配置同上(Attach方式)
AgentMain
1 | package org.example; |
MyTestMain
这里在foo中加入了递增数字a和延迟时间,以观测变化
1 | package org.example; |
MyAttachMain
1 | package org.example; |
启动
- 启动MyTestMain,效果如下
- jps看以下PID并填入MyAttachMain并保存
mvn clean package
打包- 运行MyAttachMain
- 观察MyTestMain输出结果,如下
【注意】
- 上述只显示foo是因为在MyClassVisitor中,限定了foo的调教,只要无条件输出
new MyMethodVisitor(mv, access, name, descriptor)
,即可对所有函数调用进行打印
1 | public static class MyClassVisitor extends ClassVisitor { |
- 结果如下