简介
使用JavaAgent实现一个简单的需求:方法的运行时间。这是一个很简单的例子,我们的目的是了解各种库之间的差异,做出正确的选择。
我们将学习:
- 使用ASM, Javassist和byte-buddy库实现
- 编写测试用例,运行查看效果
- 设置环境变量切换实现
使用版本
- JDK 11
- asm 9.2
- javassist 3.28
- byte-buddy 1.12.3
目标代码开发
我们要确定目标类,也就是哪些类需要处理。本项目确定一个目标类 TargetClass.java, 代码如下:
@Slf4j
public class TargetClass {
public void method1() throws InterruptedException{
log.info(">>> method1 called ");
Thread.sleep((new Random()).nextInt(1000));
}
public String method2(){
log.info(">>> method2 called ");
try {
Thread.sleep((new Random()).nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
return "end";
}
}
我们要了解这个类的方法运行时间,这里需要注意: method1 没有返回值。字节码编程时,这两个方法的处理有所不同。
我们还需要程序入口,并且创建了 TargetClass 实例,运行method1和method2方法,Main.java代码如下:
@Slf4j
public class Main {
public static void main(String[] args) throws InterruptedException {
log.info(">>> Main is running -> {}", Main.class.getName());
TargetClass target = new TargetClass();
target.method1();
target.method2();
}
}
运行程序,可以看见目标方法的执行情况。
字节码编程
我们需要一个功能统计运行时间,秒表(StopWatch.java)实现如下:
@Slf4j
public class StopWatch {
/**
*
* 静态方法实现
*
* @author PinWei Wan
* @since 1.0.1
*/
public static class StaticClazz {
static ThreadLocal<Long> t = new ThreadLocal<Long>();
public static void start() {
t.set(System.currentTimeMillis());
}
public static void end() {
final long elapseOfTime = System.currentTimeMillis() - t.get();
log.info("{} elapse of time: {}", Thread.currentThread().getStackTrace()[2] , elapseOfTime);
t.remove();
}
}
/**
*
* 类实现
*
* @author PinWei Wan
* @since 1.0.1
*/
public static class Clazz {
private final String methodName;
private long start;
public Clazz(String methodName) {
this.methodName = methodName;
}
public void start() {
start = System.currentTimeMillis();
}
public void end() {
final long elapseOfTime = System.currentTimeMillis() - start;
log.info("{} elapse of time: {}", methodName , elapseOfTime);
}
}
}
这里有两种实现:类和静态类,为什么呢?字节码编程是很专业的,需要学习库的语法,使用静态类可以降低实现需求的难度。
我们先实现需求,对目标类方法编程,ASM库实现(TransformerWithASM.java):
public class TransformerWithASM implements Transformer{
private final static String TARGET_CLASS = "io/github/kavahub/learnjava/TargetClass";
@Override
public void transform(String args, Instrumentation inst) {
inst.addTransformer(new ClassFileTransformer() {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
log.info("transform class - " + className);
// 仅处理TargetClass类
if (className.equals(TARGET_CLASS)) {
ElapseOfTimeClassWriter writer = new ElapseOfTimeClassWriter(classfileBuffer);
return writer.perform();
}
return ClassFi


863

被折叠的 条评论
为什么被折叠?



