java agent的使用【通俗易懂版】
一、静态代理Agent
1.生成Agent的jar包
(1)创建Agent项目,引入javassist.jar包
(2)编写premain方法
import java.lang.instrument.Instrumentation;public class Agent1 {public static void premain(String agentArgs, Instrumentation inst) {System.out.println("agentArgs : " + agentArgs);MyAgentTransfer trans = new MyAgentTransfer();MyAgentTransferboot trans_boot = new MyAgentTransferboot();inst.addTransformer(trans, true);inst.addTransformer(trans_boot, true);}}
(3)创建MyAgentTransferboot类,实现ClassFileTransformer接口,重写transform方法
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CodeConverter;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;
import javassist.expr.ExprEditor;
import javassist.expr.MethodCall;public class MyAgentTransferboot implements ClassFileTransformer{/** ClassLoader loader: 类加载器,用于加载当前类的类。 String className: 正在加载的类的名称(用斜杠分隔的形式,例如 java/lang/String)。Class<?> classBeingRedefined: 如果这个类正在被重新定义,则为其对应的 Class 对象;否则为 null。 ProtectionDomain protectionDomain: 类的保护域,提供关于类的安全权限的信息。byte[] classfileBuffer: 原始的字节码数组。 */@Overridepublic byte[] transform(ClassLoader loader, String className,Class<?> classBeingRedefined, ProtectionDomain protectionDomain,byte[] classfileBuffer) throws IllegalClassFormatException {byte[] transformed = null;
// System.out.println("Transforming className::" + className); if(!className.contains("TaxController") || !className.contains("")) {return classfileBuffer;}ClassPool pool = null; CtClass cl = null; try { pool = ClassPool.getDefault();cl = pool.makeClass(new java.io.ByteArrayInputStream(classfileBuffer));
// CtMethod aop_method = pool.get("com.jdktest.instrument.AopMethods").
// getDeclaredMethod("aopMethod");
// System.out.println(aop_method.getLongName());CodeConverter convert = new CodeConverter();if (cl.isInterface() == false) { CtMethod[] methods = cl.getDeclaredMethods(); for (int i = 0; i < methods.length; i++) { if (methods[i].isEmpty() == false) { // AOPInsertMethod(methods[i]); if(methods[i].getName().contains("getUrl") ) {System.out.println("methods[i].getName::" + methods[i].getName()); String name = methods[i].getName();methods[i].insertAt(92, "System.out.println(\"---------------Url:\" + Url);");
// methods[i].insertBefore(" System.out.println(\"TTTTTTTTTTTTTTTTTT**********************************************" +name + "\");");
// methods[i].insertBefore(" return \"100\";");}} } transformed = cl.toBytecode(); } } catch (Exception e) { System.err.println("Could not instrument " + className + ", exception : " + e.getMessage()); } finally { if (cl != null) { cl.detach(); } } return transformed; }private void AOPInsertMethod(CtMethod method) throws NotFoundException,CannotCompileException {method.instrument(new ExprEditor() { @Overridepublic void edit(MethodCall m) throws CannotCompileException { m.replace("{ long stime = System.currentTimeMillis(); $_ = $proceed($$);System.out.println(\""+ m.getClassName() + "." + m.getMethodName()+ " cost:\" + (System.currentTimeMillis() - stime) + \" ms\");}");}});
// method.insertBefore("System.out.println(\"enter method\");");
// method.insertAfter("System.out.println(\"leave method\");");}
(4)将Agent项目进行打包
(5)用压缩包方式打开生成的jar包,打开\META-INF\MANIFEST.MF文件,添加如下代码:
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Premain-Class: com.javaAgent.Agent1
2.在项目中使用agent
命令:-javaagent:jar包地址=参数
如:-javaagent:D:\Work_Code\javaAgent\StringLenAgent.jar=‘1’
-javaagent:D:\Work_Code\javaAgent\StringLenAgent.jar
二、动态代理Attach
1.生成Attach的jar包
(1)创建Attach项目,引入javassist.jar包、com.sun.tools.attach-1.8.0_jdk8u172-b11.jar包
(2)编写agentmain方法
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;public class Attach1 {public static void agentmain(String attachArgs, Instrumentation instrumentation) {System.out.println("attach agentmain启动");System.out.println("attachArgs : " + attachArgs);Class<?>[] classes = instrumentation.getAllLoadedClasses();for (Class<?> cls : classes) {String className = cls.getName();if(className.contains("TaxController")) {CtClass ctClass;try {ClassPool classPool = ClassPool.getDefault();ctClass = classPool.get(className);CtMethod[] methods = ctClass.getDeclaredMethods(); for (int i = 0; i < methods.length; i++) { if (methods[i].isEmpty() == false) { // AOPInsertMethod(methods[i]); if(methods[i].getName().contains("getUrl") ) {System.out.println("methods[i].getName::" + methods[i].getName()); String name = methods[i].getName();methods[i].insertAt(92, "System.out.println(\"---------------Url:\" + Url);");
// methods[i].insertBefore(" System.out.println(\"TTTTTTTTTTTTTTTTTT**********************************************" +name + "\");");
// methods[i].insertBefore(" return \"100\";");}} } ClassDefinition classDefinition = new ClassDefinition(cls, ctClass.toBytecode());instrumentation.redefineClasses(classDefinition);} catch (Throwable e) {System.out.println(e.getMessage());e.printStackTrace();}}
(3)将Attach项目进行打包
(4)用压缩包方式打开生成的jar包,打开\META-INF\MANIFEST.MF文件,添加如下代码:
Agent-Class: com.javaAttach.Attach1
Can-Redefine-Classes: true
Can-Retransform-Classes: true
(5)启动需被代理的应用程序
编写main方法,给需被代理的应用程序添加代理
import java.util.concurrent.TimeUnit;
import com.sun.tools.attach.*;public class AttachUseMain {public static void main(String[] args) throws Exception{System.out.println("AttachUseMain启动");long start = System.currentTimeMillis();System.out.println(start);for (VirtualMachineDescriptor vmd : VirtualMachine.list()) {String name = vmd.displayName();System.out.println(name + ":" + vmd.id());if (name.contains("Application")) {VirtualMachine vm = VirtualMachine.attach(vmd.id());
// vm.loadAgent("D:\\Work_Code\\javaAgent\\StringLenAttach.jar=hello,ok,aa,bb,cc=3");vm.loadAgent("D:\\Work_Code\\javaAgent_1\\javaAttach\\StringLenAttach004.jar=22");TimeUnit.MINUTES.sleep(1);vm.detach();System.out.println("Agent 已成功附加到目标 JVM");}}long end = System.currentTimeMillis();System.out.println(end - start);
// String targetPid = "25304"; //jps -l
// // 指定要附加的 Agent JAR 路径
// String agentPath = "D:\\Work_Code\\javaAgent\\StringLenAttach.jar";
//
// // 附加到目标 JVM
// VirtualMachine vm = VirtualMachine.attach(targetPid);
// // 加载 Agent
// vm.loadAgent(agentPath);
// // 断开连接
// vm.detach();System.out.println("over");}
}