常见的Java字节码增强技术对比图
对比总结
| 特性 | Javassist | ASM | Byte Buddy | CGLIB |
|---|---|---|---|---|
| 易用性 | 简单,接近源码 | 难,需要了解字节码细节 | 简单,流式 API | 较简单 |
| 性能 | 较低 | 最高 | 较高,低于 ASM | 高 |
| 灵活性 | 高 | 极高 | 高 | 较低 |
| 学习曲线 | 平缓 | 陡峭 | 平缓 | 平缓 |
| 支持范围 | 动态生成、增强 | 所有字节码操作 | 动态生成、增强 | 类代理,不支持接口代理 |
| 典型应用场景 | 动态生成类,方法增强 | 框架底层、高性能增强 | 动态代理,类生成 | 类增强(如事务代理) |
选择建议
- 性能优先:选择 ASM,适合框架开发或对性能有极高要求的场景。
- 开发效率优先:选择 Byte Buddy 或 Javassist,适合日常开发或快速实现增强。
- 简单增强:CGLIB(适合类代理)或 Javassist(快速操作类)。
- 复杂逻辑增强:Byte Buddy 提供灵活性和简洁性,适合大多数增强需求。
Skywalking采用的就是Byte Buddy技术,依赖的核心jar包如下:
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
</dependency>
<-- Agent 支持模块(如果需要通过 Java Agent 扩展运行时类)!-->
<-- skywalking就是使用该模式 !-->
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-agent</artifactId>
</dependency>
<-- ASM 支持模块(如果需要更底层的字节码增强功能 !-->
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-asm</artifactId>
</dependency>
这里举一个使用Byte Buddy拦截某方法打印耗时案例:
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.SuperMethodCall;
import net.bytebuddy.matcher.ElementMatchers;
import java.lang.reflect.Method;
// 拦截器类,用于计算方法耗时
public class TimingInterceptor {
public static Object intercept(Object proxy, Method method, Object[] args, net.bytebuddy.implementation.bind.annotation.SuperCall java.util.concurrent.Callable<?> callable) throws Exception {
long startTime = System.currentTimeMillis();
try {
// 执行原始方法
return callable.call();
} finally {
long endTime = System.currentTimeMillis();
System.out.println("Method [" + method.getName() + "] executed in " + (endTime - startTime) + "ms");
}
}
}
// 被代理的目标类
class SampleClass {
public void doWork() throws InterruptedException {
System.out.println("Doing some work...");
Thread.sleep(500); // 模拟耗时任务
}
}
// 主类
public class ByteBuddyTimingExample {
public static void main(String[] args) throws Exception {
// 使用 Byte Buddy 动态代理目标类
SampleClass proxy = new ByteBuddy()
.subclass(SampleClass.class)
.method(ElementMatchers.named("doWork")) // 匹配目标方法
.intercept(MethodDelegation.to(TimingInterceptor.class).andThen(SuperMethodCall.INSTANCE)) // 拦截并调用原始方法
.make()
.load(SampleClass.class.getClassLoader())
.getLoaded()
.getDeclaredConstructor()
.newInstance();
// 调用代理后的方法
proxy.doWork();
}
}
执行结果:
Doing some work...
Method [doWork] executed in 500ms