写在前面
本文看下如何实现打印方法耗时和入参。
1:程序
- 需要增强的类:
public class ApiTest1 {
public Integer strToInt(String str01, String str02) {
return Integer.parseInt(str01);
}
}
- 插桩类
package com.dahuyou.javassist.huohuo.aa;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import java.lang.reflect.Method;
public class MyDoIt extends ClassLoader {
public static void main(String[] args) throws Exception {
ClassPool pool = ClassPool.getDefault();
// 获取类和方法
CtClass ctClass = pool.get(ApiTest1.class.getName());
ctClass.replaceClassName("ApiTest1", "ApiTest12");
String clazzName = ctClass.getName();
CtMethod ctMethod = ctClass.getDeclaredMethod("strToInt");
// 定义局部变量 注意必须声明,而不能直接在代码中写int xx = 222;这种,否则会报CannotCompileException: [source error] no such field: xxx
ctMethod.addLocalVariable("startTime", CtClass.longType);
ctMethod.addLocalVariable("incomingParameters", pool.get(Object[].class.getName()));
// 方法前加强
// ctMethod.insertBefore("{ startTime = System.nanoTime(); incomingParameters = new Object[]{$1, $2}; }");
ctMethod.insertBefore("{ startTime = System.nanoTime(); incomingParameters = new Object[2]; incomingParameters[0] = $1; incomingParameters[1] = $2; }");
// 方法后加强,输出耗时和参数
ctMethod.insertAfter("System.out.println(\"执行耗时:\" + (System.nanoTime() - startTime));");
// 测试调用
byte[] bytes = ctClass.toBytecode();
Class<?> clazzNew = new MyDoIt().defineClass("com.dahuyou.javassist.huohuo.aa.ApiTest1", bytes, 0, bytes.length);
// 反射运行测试
Class aClass = clazzNew;
Object obj = aClass.newInstance();
Method main = aClass.getDeclaredMethod("strToInt", String.class, String.class);
main.invoke(obj, "99", "87");
// System.out.println("执行耗时:" + (System.nanoTime() - startTime));
ctClass.writeFile();
}
}
insertBefore和insertAfter分别用来在方法的开始和结束插入代码。
运行:
执行耗时:48000
Process finished with exit code 0
- 查看生成的字节码