java agent 运行期织入【yetdone】(javassist)
https://www.cnblogs.com/silyvin/p/11260965.html,
此前对javaagent的使用是在类加载期,需要重启应用才能织入,本次实践java agent运行期织入
- premain是静态修改,在类加载之前修改; attach是动态修改,在类加载后修改
- 要使premain生效重启应用,而attach不重启应用即可修改字节码并让其重新加载
可以看到attach的方式更加强大,其核心原理首先是找到相关的进程id, 然后根据进程id去动态修改相关字节码
还是参考这篇文章:https://www.jianshu.com/p/b2d09a78678d
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.22.0-GA</version>
</dependency>
public static void agentmain(String agentArgs, Instrumentation inst)
throws ClassNotFoundException, UnmodifiableClassException,
InterruptedException {
System.out.println("Agent Main start " + agentArgs);
inst.addTransformer(new MyTransformer(), true);
Class[] classes = inst.getAllLoadedClasses();
for(Class c : classes) {
if(c.getName().indexOf("MyClient") != -1)
inst.retransformClasses(c);
}
}
package agent;
//
//import com.sun.tools.attach.VirtualMachine;无法通过编译
import javassist.ClassPool;
import javassist.CtBehavior;
import javassist.CtClass;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.lang.reflect.Method;
import java.security.ProtectionDomain;
/**
* https://www.cnblogs.com/silyvin/p/11260965.html
* https://www.cnblogs.com/silyvin/p/11336727.html
* Created by sunyuming on 19/7/28.
*/
public class MyTransformer implements ClassFileTransformer {
private ClassPool classPool = new ClassPool(true);
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if(className.equals("agent/MyClient")) {
System.out.println("类 " + className);
try {
CtClass ctClass = classPool.makeClass(new ByteArrayInputStream(classfileBuffer));
for(CtBehavior ctBehavior : ctClass.getDeclaredBehaviors()) {
if(ctBehavior.getLongName().equals("agent.MyClient.print()")) {
System.out.println("开始处理方法 " + ctBehavior.getLongName());
ctBehavior.insertBefore("System.out.println(\"前置aop\");");
ctBehavior.insertAfter("System.out.println(\"后置aop\");");
}
}
return ctClass.toBytecode();
} catch (Exception e) {
e.printStackTrace();
return null;
}
} else
return null;
}
public static void agentmain(String agentArgs, Instrumentation inst)
throws ClassNotFoundException, UnmodifiableClassException,
InterruptedException {
System.out.println("Agent Main start " + agentArgs);
inst.addTransformer(new MyTransformer(), true);
inst.retransformClasses(MyClient.class);
}
public static void premain(String args, Instrumentation instrumentation) {
System.out.println("开始premain " + args);
ClassFileTransformer classFileTransformer = new MyTransformer();
instrumentation.addTransformer(classFileTransformer);
}
/**
* premain
* MANIFEST.MF.premain
* cp target/MyTest-1.0-SNAPSHOT-jar-with-dependencies.jar ~/Documents/tool/jars/myagentpre.jar
* MANIFEST.MF
* java -javaagent:/Users/sunyuming/Documents/tool/jars/myagentpre.jar=sun -jar target/MyTest-1.0-SNAPSHOT-jar-with-dependencies.jar
*/
/**
* agentmain
* MANIFEST.MF
* cp target/MyTest-1.0-SNAPSHOT-jar-with-dependencies.jar ~/Documents/tool/jars/myagented.jar
* java -jar ~/Documents/tool/jars/myagented.jar
* 另一个terminal
* MANIFEST.MF.agentmain
* jps
* java -Djava.ext.dirs=${JAVA_HOME}/lib -jar target/MyTest-1.0-SNAPSHOT-jar-with-dependencies.jar 47929
*/
public static void main(String [] args) throws Exception {
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Class vmClass = classLoader.loadClass("com.sun.tools.attach.VirtualMachine");
Object vm = vmClass.getMethod("attach", String.class).invoke(null, args[0]);
String path = MyTransformer.class.getProtectionDomain().getCodeSource().getLocation().getPath();
// main与agentmain也可以分开,体现在path上,我们这边合并
vmClass.getMethod("loadAgent", String.class, String.class).invoke(vm, path, "");
// 无法通过编译,除非在pom中加入tool,即使如此,运行期也需要 -Djava.ext.dirs=${JAVA_HOME}/lib
// VirtualMachine vm = VirtualMachine.attach(args[0]); //正在运行的java 程序 ps id
// vm.loadAgent("/Users/sunyuming/work/MyTest/target/MyTest-1.0-SNAPSHOT-jar-with-dependencies.jar");
}
}
被注入的jar
Manifest-Version: 1.0 Main-Class: agent.MyClient
agent
Manifest-Version: 1.0 Main-Class: agent.MyTransformer Agent-Class: agent.MyTransformer Can-Redefine-Classes: true Can-Retransform-Classes: true
premain
Manifest-Version: 1.0 Premain-Class: agent.MyTransformer

2个附属:
1)也许以后补充一个asm
2)配置文件是否可以?
浙公网安备 33010602011771号