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.agentattach
- Sample.java
- TestMain.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
动态 Attach 的 agent 与通过 JVM 启动 javaagent 参数指定的 agent jar 包的方式有所差异,动态 Attach 的 agent 会执行 agentmain 方法,而不是 premain 方法。- 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 的完备包路径。- 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,我们提供一个不绝循环的测试类:- 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
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |