Net ByteBuddy 是 Java 世界里"运行时动态生成字节码"的一把瑞士军刀------
官方口号:"Code like a Pro, intercept like a Boss."
用纯 API 就能在 "零编译、零源码" 的前提下:
- 动态创建子类 / 接口实现
- 拦截(改写)任意方法(包括 final、static、private)
- 给类加字段、加注解、加接口
- 生成 Lambda、访问者、代理、AOP 切面、Mock 桩......
而且语法像 fluent-builder,写起来比手写 ASM 舒服 10 倍,性能又比 CGLib / Javassist 高一头;
Spring Framework 5.3+、Mockito 2+、Hibernate 6 都把它当默认字节码引擎。
一句话定位
"ByteBuddy = ASM 的脚手架 + CGLib 的易用性 + Java-Agent 的侵入能力"
核心概念(中文速记)
| 英文术语 | 白话解释 | 对应代码入口 |
|---|---|---|
ByteBuddy |
工厂大吊车,一切动态类型的起点 | new ByteBuddy() |
DynamicType |
正在"搭建"的类,还没落盘 | .subclass(Xxx.class) |
ElementMatcher |
"谁"要被拦截------方法/字段/注解过滤 | ElementMatchers.any() |
Implementation |
拦截后"怎么干"------固定值、调用父类、转发、自定义 | MethodDelegation.to(MyInterceptor.class) |
Unloaded |
已生成字节码但未加载,可 .saveIn() 落盘调试 |
dynamicType.make() |
Loaded |
已经进 JVM 的 Class,可直接 newInstance() |
type.load(getClass().getClassLoader()) |
10 行代码速通(动态子类 + 方法拦截)
xml
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.14.16</version>
</dependency>
java
// 1. 定义拦截器:所有方法都转发到这里
public class TimeInterceptor {
@RuntimeType
public Object intercept(@Origin Method method,
@SuperCall Callable<?> zuper) throws Exception {
long start = System.nanoTime();
try { return zuper.call(); } // 继续原实现
finally { System.out.println(method + " 耗时 " + (System.nanoTime()-start)/1_000_000 + " ms"); }
}
}
// 2. 运行时生成子类并加载
Class<? extends ArrayList> dynamicType = new ByteBuddy()
.subclass(ArrayList.class) // 我要继承 ArrayList
.method(ElementMatchers.any()) // 拦截所有方法
.intercept(MethodDelegation.to(TimeInterceptor.class))
.make()
.load(getClass().getClassLoader())
.getLoaded();
// 3. 像正常类一样用
List<String> list = dynamicType.getDeclaredConstructor().newInstance();
list.add("byte");
list.add("buddy");
System.out.println(list); // 输出内容 + 每方法耗时
常见玩法地图
-
给接口快速生成实现类(MyBatis Mapper 那种)
javanew ByteBuddy() .implement(UserMapper.class) .intercept(MethodDelegation.to(sqlSession)); -
运行时重新加载已存在的类(Java-Agent 热补丁)
javaByteBuddyAgent.install(); // attach 到当前 JVM new ByteBuddy() .redefine(FooService.class) .method(named("calc")).intercept(FixedValue.value(42)) .installOnByteBuddyAgent(); -
生成 Lambda 的"元工厂"字节码,提升反射调用速度(Spring 5.3 内部用它替代 CGLib)。
-
单元测试 Mock 桩(Mockito 2 默认底层就是 ByteBuddy)。
性能 & 体积
- 生成速度:首次约 1~3 ms / 类,之后内部缓存 < 0.1 ms。
- 运行速度:接近手写子类,无反射开销(生成的字节码里直接
invokespecial/invokevirtual)。 - 依赖体积:核心
byte-buddy-1.14.x.jar仅 3.5 MB,无 Native 代码。
一句话总结
"只要你会写 fluent API,就能在运行时'凭空'造出任何 Java 类,并让它按你的规则跑------这就是 ByteBuddy。"