ByteBuddy 实战指南:Java字节码增强利器
一、ByteBuddy简介
1.1 什么是ByteBuddy
ByteBuddy是一个强大的Java字节码操作库,它能够在运行时动态生成和修改Java类。相比于传统的ASM、Javassist等字节码框架,ByteBuddy提供了更加简洁、类型安全的API,使得字节码操作变得优雅而高效。
ByteBuddy的核心优势:
- 🎯 类型安全:基于流式API,编译期检查
- 🚀 性能优越:生成的代码性能接近手写
- 💡 简单易用:无需深入理解字节码指令
- 🔧 功能强大:支持类生成、方法拦截、代理等
- 🌟 广泛应用:Hibernate、Mockito、Spring等框架都在使用
1.2 应用场景
ByteBuddy典型应用场景:
┌─────────────────────────────────────────────────────┐
│ 应用场景 │
├─────────────────────────────────────────────────────┤
│ • AOP切面编程 - 方法拦截、日志、权限控制 │
│ • 性能监控 - 方法耗时统计、调用链追踪 │
│ • Mock测试 - 动态生成测试桩 │
│ • ORM框架 - 实体代理、懒加载 │
│ • 动态代理 - 接口实现、委托模式 │
│ • Agent开发 - Java Agent、APM监控 │
│ • 热部署 - 运行时类替换 │
└─────────────────────────────────────────────────────┘
1.3 Maven依赖
xml
<dependencies>
<!-- ByteBuddy核心库 -->
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.14.10</version>
</dependency>
<!-- ByteBuddy Agent支持 -->
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-agent</artifactId>
<version>1.14.10</version>
</dependency>
<!-- 用于测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
二、ElementMatcher核心概念
2.1 什么是ElementMatcher
ElementMatcher是ByteBuddy中用于匹配和过滤类、方法、字段、注解等元素的核心接口。它类似于正则表达式,但专门用于Java程序元素的匹配。
ElementMatcher的作用:
sql
┌──────────────┐ ElementMatcher ┌──────────────┐
│ 待处理的类 │ ─────────────────────→ │ 匹配的元素 │
│ │ │ │
│ Class A │ │ Method X ✓ │
│ Class B │ 匹配规则: │ Method Y ✗ │
│ Class C │ - 方法名 │ Method Z ✓ │
│ ... │ - 注解 │ ... │
│ │ - 参数类型 │ │
└──────────────┘ - 返回值类型 └──────────────┘
- 修饰符
2.2 ElementMatchers工具类
ByteBuddy提供了ElementMatchers工具类,包含大量预定义的匹配器:
java
package com.example.bytebuddy;
import net.bytebuddy.matcher.ElementMatchers;
import static net.bytebuddy.matcher.ElementMatchers.*;
/**
* ElementMatchers常用方法示例
*/
public class ElementMatcherBasics {
public static void main(String[] args) {
// 1. 类匹配器
named("com.example.UserService"); // 匹配指定类名
nameStartsWith("com.example"); // 匹配包名前缀
nameEndsWith("Service"); // 匹配类名后缀
nameContains("Controller"); // 包含指定字符串
// 2. 方法匹配器
named("save"); // 匹配方法名
isPublic(); // 公共方法
isStatic(); // 静态方法
returns(String.class); // 返回值类型
takesArguments(2); // 参数数量
takesArgument(0, String.class); // 第一个参数类型
// 3. 注解匹配器
isAnnotatedWith(Override.class); // 有@Override注解
isAnnotatedWith(named("MyAnnotation")); // 有指定注解
// 4. 继承关系匹配器
isSubTypeOf(List.class); // 是List的子类
hasSuperType(named("BaseService")); // 有指定父类
// 5. 逻辑组合
named("save").and(isPublic()); // 与运算
named("get").or(named("set")); // 或运算
not(isStatic()); // 非运算
any(); // 匹配任何元素
none(); // 不匹配任何元素
}
}
三、基础实战:动态创建类
3.1 创建简单类
java
package com.example.bytebuddy.basic;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.FixedValue;
import static net.bytebuddy.matcher.ElementMatchers.*;
/**
* 动态创建类示例
*/
public class CreateClassDemo {
public static void main(String[] args) throws Exception {
// 1. 创建一个Object的子类
Class<?> dynamicType = new ByteBuddy()
.subclass(Object.class)
.name("com.example.DynamicClass")
.make()
.load(CreateClassDemo.class.getClassLoader())
.getLoaded();
System.out.println("创建的类: " + dynamicType.getName());
System.out.println("实例: " + dynamicType.newInstance());
System.out.println("\n" + "=".repeat(60) + "\n");
// 2. 创建带方法的类
Class<?> helloWorld = new ByteBuddy()
.subclass(Object.class)
.name("com.example.HelloWorld")
.method(named("toString")) // 匹配toString方法
.intercept(FixedValue.value("Hello ByteBuddy!")) // 返回固定值
.make()
.load(CreateClassDemo.class.getClassLoader())
.getLoaded();
Object instance = helloWorld.newInstance();
System.out.println("toString结果: " + instance.toString());
System.out.println("\n" + "=".repeat(60) + "\n");
// 3. 定义自定义方法
Class<?> calculator = new ByteBuddy()
.subclass(Object.class)
.name("com.example.Calculator")
.defineMethod("add", int.class, Visibility.PUBLIC)
.withParameters(int.class, int.class)
.intercept(FixedValue.value(42)) // 暂时返回固定值
.make()
.load(CreateClassDemo.class.getClassLoader())
.getLoaded();
Object calc = calculator.newInstance();
int result = (int) calculator.getMethod("add", int.class, int.class)
.invoke(calc, 10, 20);
System.out.println("add(10, 20) = " + result);
}
}
输出结果:
makefile
创建的类: com.example.DynamicClass
实例: com.example.DynamicClass@7f31245a
============================================================
toString结果: Hello ByteBuddy!
============================================================
add(10, 20) = 42
3.2 方法委托(Delegation)
java
package com.example.bytebuddy.basic;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.*;
import static net.bytebuddy.matcher.ElementMatchers.*;
/**
* 方法委托示例
*/
public class MethodDelegationDemo {
/**
* 拦截器类
*/
public static class LogInterceptor {
@RuntimeType
public static Object intercept(@Origin String methodName,
@SuperCall Callable<?> zuper,
@AllArguments Object[] args) throws Exception {
System.out.println("[Before] 调用方法: " + methodName);
System.out.println("[Before] 参数: " + java.util.Arrays.toString(args));
long start = System.currentTimeMillis();
Object result = zuper.call(); // 调用原方法
long end = System.currentTimeMillis();
System.out.println("[After] 返回值: " + result);
System.out.println("[After] 耗时: " + (end - start) + "ms");
return result;
}
}
/**
* 待增强的原始类
*/
public static class UserService {
public String findUser(Long id) {
try {
Thread.sleep(100); // 模拟数据库查询
} catch (InterruptedException e) {
e.printStackTrace();
}
return "User-" + id;
}
public void saveUser(String name, int age) {
System.out.println(" [原方法] 保存用户: " + name + ", 年龄: " + age);
}
}
public static void main(String[] args) throws Exception {
// 使用ByteBuddy增强UserService
Class<?> dynamicType = new ByteBuddy()
.subclass(UserService.class)
.method(any()) // 匹配所有方法
.intercept(MethodDelegation.to(LogInterceptor.class))
.make()
.load(MethodDelegationDemo.class.getClassLoader())
.getLoaded();
UserService userService = (UserService) dynamicType.newInstance();
// 调用方法
System.out.println("====== 测试 findUser ======");
String user = userService.findUser(123L);
System.out.println("最终结果: " + user);
System.out.println("\n====== 测试 saveUser ======");
userService.saveUser("张三", 25);
}
}
输出结果:
ini
====== 测试 findUser ======
[Before] 调用方法: findUser
[Before] 参数: [123]
[After] 返回值: User-123
[After] 耗时: 102ms
最终结果: User-123
====== 测试 saveUser ======
[Before] 调用方法: saveUser
[Before] 参数: [张三, 25]
[原方法] 保存用户: 张三, 年龄: 25
[After] 返回值: null
[After] 耗时: 1ms
四、ElementMatcher高级用法
4.1 方法匹配器组合
java
package com.example.bytebuddy.matcher;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatcher;
import java.lang.reflect.Method;
import static net.bytebuddy.matcher.ElementMatchers.*;
/**
* 复杂的ElementMatcher组合示例
*/
public class AdvancedMatcherDemo {
public static class LogInterceptor {
public static String intercept() {
return "Intercepted!";
}
}
public static class DemoService {
public String publicMethod() { return "public"; }
private String privateMethod() { return "private"; }
protected String protectedMethod() { return "protected"; }
public static String staticMethod() { return "static"; }
public final String finalMethod() { return "final"; }
public String getName() { return "name"; }
public void setName(String name) { }
public String findById(Long id) { return "User-" + id; }
public String findByName(String name) { return "User-" + name; }
public int calculate(int a, int b) { return a + b; }
}
public static void main(String[] args) throws Exception {
// 1. 匹配public非static方法
ElementMatcher.Junction<Method> matcher1 =
isPublic().and(not(isStatic()));
System.out.println("====== 匹配: public非static方法 ======");
printMatches(DemoService.class, matcher1);
// 2. 匹配getter方法(名字以get开头且无参数)
ElementMatcher.Junction<Method> matcher2 =
nameStartsWith("get").and(takesArguments(0));
System.out.println("\n====== 匹配: getter方法 ======");
printMatches(DemoService.class, matcher2);
// 3. 匹配setter方法(名字以set开头且有1个参数)
ElementMatcher.Junction<Method> matcher3 =
nameStartsWith("set").and(takesArguments(1));
System.out.println("\n====== 匹配: setter方法 ======");
printMatches(DemoService.class, matcher3);
// 4. 匹配所有find开头的方法
ElementMatcher.Junction<Method> matcher4 =
nameStartsWith("find");
System.out.println("\n====== 匹配: find*方法 ======");
printMatches(DemoService.class, matcher4);
// 5. 匹配返回String类型的方法
ElementMatcher.Junction<Method> matcher5 =
returns(String.class);
System.out.println("\n====== 匹配: 返回String的方法 ======");
printMatches(DemoService.class, matcher5);
// 6. 匹配第一个参数为Long的方法
ElementMatcher.Junction<Method> matcher6 =
takesArgument(0, Long.class);
System.out.println("\n====== 匹配: 第一个参数为Long的方法 ======");
printMatches(DemoService.class, matcher6);
// 7. 复杂组合:public + 非static + 返回String + 参数为1个
ElementMatcher.Junction<Method> matcher7 =
isPublic()
.and(not(isStatic()))
.and(returns(String.class))
.and(takesArguments(1));
System.out.println("\n====== 匹配: 复杂组合条件 ======");
printMatches(DemoService.class, matcher7);
}
private static void printMatches(Class<?> clazz, ElementMatcher<? super Method> matcher) {
for (Method method : clazz.getDeclaredMethods()) {
if (matcher.matches(method)) {
System.out.println(" ✓ " + method.getName() + " - " + method);
}
}
}
}
4.2 注解匹配器
java
package com.example.bytebuddy.matcher;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import java.lang.annotation.*;
import java.util.concurrent.Callable;
import static net.bytebuddy.matcher.ElementMatchers.*;
/**
* 基于注解的方法匹配
*/
public class AnnotationMatcherDemo {
/**
* 自定义日志注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Logged {
String value() default "";
}
/**
* 自定义缓存注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Cacheable {
int ttl() default 60; // 缓存时间(秒)
}
/**
* 日志拦截器
*/
public static class LoggingInterceptor {
@RuntimeType
public static Object intercept(@SuperCall Callable<?> zuper) throws Exception {
System.out.println("[LOG] 方法执行开始");
Object result = zuper.call();
System.out.println("[LOG] 方法执行结束");
return result;
}
}
/**
* 缓存拦截器
*/
public static class CacheInterceptor {
private static final java.util.Map<String, Object> cache = new java.util.HashMap<>();
@RuntimeType
public static Object intercept(@SuperCall Callable<?> zuper,
@net.bytebuddy.implementation.bind.annotation.Origin
String methodName) throws Exception {
if (cache.containsKey(methodName)) {
System.out.println("[CACHE] 命中缓存: " + methodName);
return cache.get(methodName);
}
System.out.println("[CACHE] 未命中,执行方法: " + methodName);
Object result = zuper.call();
cache.put(methodName, result);
return result;
}
}
/**
* 业务服务类
*/
public static class ProductService {
@Logged
public String getProductName(Long id) {
System.out.println(" [执行] 查询产品名称: " + id);
return "Product-" + id;
}
@Cacheable(ttl = 300)
public Double getProductPrice(Long id) {
System.out.println(" [执行] 查询产品价格: " + id);
return 99.99;
}
@Logged
@Cacheable
public String getProductDetail(Long id) {
System.out.println(" [执行] 查询产品详情: " + id);
return "Detail-" + id;
}
public void updateProduct(Long id, String name) {
System.out.println(" [执行] 更新产品: " + id + " -> " + name);
}
}
public static void main(String[] args) throws Exception {
// 1. 拦截所有带@Logged注解的方法
Class<?> loggedType = new ByteBuddy()
.subclass(ProductService.class)
.method(isAnnotatedWith(Logged.class))
.intercept(MethodDelegation.to(LoggingInterceptor.class))
.make()
.load(AnnotationMatcherDemo.class.getClassLoader())
.getLoaded();
ProductService loggedService = (ProductService) loggedType.newInstance();
System.out.println("====== 测试@Logged注解拦截 ======");
loggedService.getProductName(100L);
System.out.println();
loggedService.updateProduct(100L, "New Name"); // 没有@Logged,不拦截
System.out.println("\n" + "=".repeat(60) + "\n");
// 2. 拦截所有带@Cacheable注解的方法
Class<?> cachedType = new ByteBuddy()
.subclass(ProductService.class)
.method(isAnnotatedWith(Cacheable.class))
.intercept(MethodDelegation.to(CacheInterceptor.class))
.make()
.load(AnnotationMatcherDemo.class.getClassLoader())
.getLoaded();
ProductService cachedService = (ProductService) cachedType.newInstance();
System.out.println("====== 测试@Cacheable注解拦截 ======");
cachedService.getProductPrice(200L); // 第一次调用
System.out.println();
cachedService.getProductPrice(200L); // 第二次调用,命中缓存
System.out.println("\n" + "=".repeat(60) + "\n");
// 3. 同时拦截多个注解(链式拦截)
Class<?> multiType = new ByteBuddy()
.subclass(ProductService.class)
.method(isAnnotatedWith(Logged.class))
.intercept(MethodDelegation.to(LoggingInterceptor.class))
.method(isAnnotatedWith(Cacheable.class))
.intercept(MethodDelegation.to(CacheInterceptor.class))
.make()
.load(AnnotationMatcherDemo.class.getClassLoader())
.getLoaded();
ProductService multiService = (ProductService) multiType.newInstance();
System.out.println("====== 测试多注解拦截 ======");
multiService.getProductDetail(300L); // 有@Logged和@Cacheable
System.out.println();
multiService.getProductDetail(300L); // 第二次调用
}
}
五、生产级实战:性能监控系统
5.1 方法执行时间监控
java
package com.example.bytebuddy.production;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.*;
import java.lang.annotation.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import static net.bytebuddy.matcher.ElementMatchers.*;
/**
* 生产级性能监控系统
*/
public class PerformanceMonitor {
/**
* 监控注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Monitor {
String value() default "";
long threshold() default 1000; // 慢方法阈值(毫秒)
}
/**
* 性能指标收集器
*/
public static class MetricsCollector {
private static class MethodMetrics {
AtomicLong totalCalls = new AtomicLong(0);
AtomicLong totalTime = new AtomicLong(0);
AtomicLong maxTime = new AtomicLong(0);
AtomicLong minTime = new AtomicLong(Long.MAX_VALUE);
AtomicLong errorCount = new AtomicLong(0);
}
private static final ConcurrentHashMap<String, MethodMetrics> metricsMap =
new ConcurrentHashMap<>();
public static void recordMetric(String methodName, long duration, boolean hasError) {
MethodMetrics metrics = metricsMap.computeIfAbsent(methodName, k -> new MethodMetrics());
metrics.totalCalls.incrementAndGet();
metrics.totalTime.addAndGet(duration);
// 更新最大值
metrics.maxTime.updateAndGet(current -> Math.max(current, duration));
// 更新最小值
metrics.minTime.updateAndGet(current -> Math.min(current, duration));
if (hasError) {
metrics.errorCount.incrementAndGet();
}
}
public static void printReport() {
System.out.println("\n" + "=".repeat(80));
System.out.println("性能监控报告");
System.out.println("=".repeat(80));
System.out.printf("%-40s %10s %10s %10s %10s %10s%n",
"方法名", "调用次数", "平均耗时", "最大耗时", "最小耗时", "错误次数");
System.out.println("-".repeat(80));
metricsMap.forEach((methodName, metrics) -> {
long avgTime = metrics.totalCalls.get() > 0 ?
metrics.totalTime.get() / metrics.totalCalls.get() : 0;
System.out.printf("%-40s %10d %9dms %9dms %9dms %10d%n",
methodName,
metrics.totalCalls.get(),
avgTime,
metrics.maxTime.get(),
metrics.minTime.get() == Long.MAX_VALUE ? 0 : metrics.minTime.get(),
metrics.errorCount.get());
});
System.out.println("=".repeat(80));
}
}
/**
* 性能监控拦截器
*/
public static class MonitorInterceptor {
@RuntimeType
public static Object intercept(@SuperCall Callable<?> zuper,
@Origin String methodName,
@Origin Class<?> clazz,
@AllArguments Object[] args) throws Exception {
String fullMethodName = clazz.getSimpleName() + "." + methodName;
long start = System.currentTimeMillis();
boolean hasError = false;
Object result = null;
try {
result = zuper.call();
return result;
} catch (Exception e) {
hasError = true;
throw e;
} finally {
long duration = System.currentTimeMillis() - start;
// 记录指标
MetricsCollector.recordMetric(fullMethodName, duration, hasError);
// 检查是否超过阈值
Monitor annotation = clazz.getAnnotation(Monitor.class);
if (annotation != null && duration > annotation.threshold()) {
System.err.printf("[SLOW] %s 耗时 %dms (阈值: %dms)%n",
fullMethodName, duration, annotation.threshold());
}
}
}
}
/**
* 模拟业务服务
*/
@Monitor(threshold = 100)
public static class OrderService {
public String createOrder(Long userId, Long productId) {
sleep(50);
return "ORDER-" + System.currentTimeMillis();
}
public void processPayment(String orderId, double amount) {
sleep(80);
System.out.println(" [业务] 处理支付: " + orderId + " - " + amount);
}
public String queryOrder(String orderId) {
sleep(150); // 超过阈值
return "Order Detail: " + orderId;
}
public void cancelOrder(String orderId) {
sleep(30);
if (Math.random() > 0.7) {
throw new RuntimeException("取消订单失败");
}
System.out.println(" [业务] 订单已取消: " + orderId);
}
private void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public static void main(String[] args) throws Exception {
// 安装ByteBuddy Agent
ByteBuddyAgent.install();
// 创建增强类
new ByteBuddy()
.redefine(OrderService.class)
.method(isAnnotatedWith(Monitor.class)
.or(declaringType(isAnnotatedWith(Monitor.class))))
.intercept(MethodDelegation.to(MonitorInterceptor.class))
.make()
.load(OrderService.class.getClassLoader(),
ClassReloadingStrategy.fromInstalledAgent());
// 模拟业务调用
OrderService orderService = new OrderService();
System.out.println("====== 开始性能测试 ======\n");
// 测试1: 创建订单(10次)
for (int i = 0; i < 10; i++) {
orderService.createOrder(100L + i, 200L + i);
}
// 测试2: 处理支付(5次)
for (int i = 0; i < 5; i++) {
orderService.processPayment("ORDER-" + i, 99.99);
}
// 测试3: 查询订单(8次,超过阈值)
for (int i = 0; i < 8; i++) {
orderService.queryOrder("ORDER-" + i);
}
// 测试4: 取消订单(10次,可能有错误)
for (int i = 0; i < 10; i++) {
try {
orderService.cancelOrder("ORDER-" + i);
} catch (Exception e) {
// 忽略异常
}
}
// 打印监控报告
MetricsCollector.printReport();
}
}
5.2 数据库访问监控(模拟MyBatis)
java
package com.example.bytebuddy.production;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.*;
import java.lang.annotation.*;
import java.util.concurrent.Callable;
import static net.bytebuddy.matcher.ElementMatchers.*;
/**
* 数据库访问监控(模拟MyBatis Mapper)
*/
public class DatabaseMonitor {
/**
* SQL查询注解(模拟MyBatis的@Select)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Select {
String value();
}
/**
* SQL更新注解(模拟MyBatis的@Update)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Update {
String value();
}
/**
* SQL拦截器
*/
public static class SqlInterceptor {
private static final ThreadLocal<Integer> queryDepth = ThreadLocal.withInitial(() -> 0);
@RuntimeType
public static Object intercept(@SuperCall Callable<?> zuper,
@Origin String methodName,
@AllArguments Object[] args,
@Origin java.lang.reflect.Method method) throws Exception {
// 获取SQL语句
String sql = null;
Select select = method.getAnnotation(Select.class);
Update update = method.getAnnotation(Update.class);
if (select != null) {
sql = select.value();
} else if (update != null) {
sql = update.value();
}
if (sql == null) {
return zuper.call();
}
// 增加调用深度
int depth = queryDepth.get();
queryDepth.set(depth + 1);
String indent = " ".repeat(depth);
long start = System.currentTimeMillis();
System.out.println(indent + "[SQL] 执行SQL: " + sql);
System.out.println(indent + "[SQL] 参数: " + java.util.Arrays.toString(args));
try {
Object result = zuper.call();
long duration = System.currentTimeMillis() - start;
System.out.println(indent + "[SQL] 耗时: " + duration + "ms");
// 检测慢SQL
if (duration > 100) {
System.err.println(indent + "[WARN] 慢SQL检测: " + sql +
" (耗时: " + duration + "ms)");
}
return result;
} finally {
queryDepth.set(depth);
}
}
}
/**
* Mapper接口
*/
public interface UserMapper {
@Select("SELECT * FROM users WHERE id = ?")
User findById(Long id);
@Select("SELECT * FROM users WHERE name = ?")
User findByName(String name);
@Update("UPDATE users SET name = ? WHERE id = ?")
int updateName(String name, Long id);
@Update("DELETE FROM users WHERE id = ?")
int deleteById(Long id);
}
/**
* 实体类
*/
public static class User {
private Long id;
private String name;
private int age;
public User(Long id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{id=" + id + ", name='" + name + "', age=" + age + "}";
}
}
/**
* Mapper实现类(模拟)
*/
public static class UserMapperImpl implements UserMapper {
@Override
public User findById(Long id) {
simulateDbQuery(80);
return new User(id, "User-" + id, 25);
}
@Override
public User findByName(String name) {
simulateDbQuery(120); // 慢查询
return new User(1L, name, 30);
}
@Override
public int updateName(String name, Long id) {
simulateDbQuery(50);
return 1;
}
@Override
public int deleteById(Long id) {
simulateDbQuery(60);
return 1;
}
private void simulateDbQuery(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public static void main(String[] args) throws Exception {
// 创建增强的Mapper
Class<?> enhancedMapper = new ByteBuddy()
.subclass(UserMapperImpl.class)
.method(isAnnotatedWith(Select.class)
.or(isAnnotatedWith(Update.class)))
.intercept(MethodDelegation.to(SqlInterceptor.class))
.make()
.load(DatabaseMonitor.class.getClassLoader())
.getLoaded();
UserMapper mapper = (UserMapper) enhancedMapper.newInstance();
System.out.println("====== 数据库访问监控测试 ======\n");
// 测试查询
System.out.println("1. 根据ID查询用户:");
User user1 = mapper.findById(100L);
System.out.println("结果: " + user1);
System.out.println("\n2. 根据名称查询用户(慢查询):");
User user2 = mapper.findByName("张三");
System.out.println("结果: " + user2);
System.out.println("\n3. 更新用户名:");
int affected = mapper.updateName("李四", 100L);
System.out.println("影响行数: " + affected);
System.out.println("\n4. 删除用户:");
int deleted = mapper.deleteById(100L);
System.out.println("删除行数: " + deleted);
}
}
六、实战案例:Spring AOP增强
6.1 自定义事务管理
java
package com.example.bytebuddy.spring;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.*;
import java.lang.annotation.*;
import java.util.concurrent.Callable;
import static net.bytebuddy.matcher.ElementMatchers.*;
/**
* 自定义事务管理(模拟Spring @Transactional)
*/
public class TransactionManager {
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Transactional {
Propagation propagation() default Propagation.REQUIRED;
boolean readOnly() default false;
}
public enum Propagation {
REQUIRED, REQUIRES_NEW, SUPPORTS, MANDATORY
}
/**
* 事务上下文
*/
public static class TransactionContext {
private static final ThreadLocal<Boolean> inTransaction = new ThreadLocal<>();
private static final ThreadLocal<Boolean> readOnly = new ThreadLocal<>();
public static void begin(boolean readOnly) {
inTransaction.set(true);
TransactionContext.readOnly.set(readOnly);
System.out.println(" [TX] 开启事务 (readOnly=" + readOnly + ")");
}
public static void commit() {
if (Boolean.TRUE.equals(inTransaction.get())) {
System.out.println(" [TX] 提交事务");
clear();
}
}
public static void rollback() {
if (Boolean.TRUE.equals(inTransaction.get())) {
System.err.println(" [TX] 回滚事务");
clear();
}
}
private static void clear() {
inTransaction.remove();
readOnly.remove();
}
public static boolean isInTransaction() {
return Boolean.TRUE.equals(inTransaction.get());
}
}
/**
* 事务拦截器
*/
public static class TransactionInterceptor {
@RuntimeType
public static Object intercept(@SuperCall Callable<?> zuper,
@Origin String methodName,
@Origin java.lang.reflect.Method method) throws Exception {
Transactional tx = method.getAnnotation(Transactional.class);
if (tx == null) {
return zuper.call();
}
boolean shouldManageTx = !TransactionContext.isInTransaction();
if (shouldManageTx) {
TransactionContext.begin(tx.readOnly());
}
try {
Object result = zuper.call();
if (shouldManageTx) {
TransactionContext.commit();
}
return result;
} catch (Exception e) {
if (shouldManageTx) {
TransactionContext.rollback();
}
throw e;
}
}
}
/**
* 服务类
*/
public static class AccountService {
@Transactional
public void transfer(Long fromId, Long toId, double amount) {
System.out.println(" [业务] 执行转账: " + fromId + " -> " + toId + " 金额: " + amount);
deduct(fromId, amount);
add(toId, amount);
System.out.println(" [业务] 转账成功");
}
@Transactional
public void transferWithError(Long fromId, Long toId, double amount) {
System.out.println(" [业务] 执行转账(会失败): " + fromId + " -> " + toId);
deduct(fromId, amount);
// 模拟错误
throw new RuntimeException("余额不足");
}
@Transactional(readOnly = true)
public double getBalance(Long accountId) {
System.out.println(" [业务] 查询余额: " + accountId);
return 1000.0;
}
private void deduct(Long accountId, double amount) {
System.out.println(" [业务] 扣款: " + accountId + " - " + amount);
}
private void add(Long accountId, double amount) {
System.out.println(" [业务] 入账: " + accountId + " + " + amount);
}
}
public static void main(String[] args) throws Exception {
Class<?> enhancedClass = new ByteBuddy()
.subclass(AccountService.class)
.method(isAnnotatedWith(Transactional.class))
.intercept(MethodDelegation.to(TransactionInterceptor.class))
.make()
.load(TransactionManager.class.getClassLoader())
.getLoaded();
AccountService service = (AccountService) enhancedClass.newInstance();
System.out.println("====== 测试1: 正常转账 ======");
service.transfer(1L, 2L, 100.0);
System.out.println("\n====== 测试2: 查询余额(只读事务) ======");
double balance = service.getBalance(1L);
System.out.println("余额: " + balance);
System.out.println("\n====== 测试3: 转账失败(事务回滚) ======");
try {
service.transferWithError(1L, 2L, 200.0);
} catch (Exception e) {
System.out.println("捕获异常: " + e.getMessage());
}
}
}
七、ByteBuddy Agent开发
7.1 Java Agent基础
java
package com.example.bytebuddy.agent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.*;
import java.lang.instrument.Instrumentation;
import java.util.concurrent.Callable;
import static net.bytebuddy.matcher.ElementMatchers.*;
/**
* ByteBuddy Java Agent示例
*
* 编译后使用方式:
* java -javaagent:agent.jar -jar app.jar
*/
public class PerformanceAgent {
/**
* Agent入口方法
*/
public static void premain(String arguments, Instrumentation instrumentation) {
System.out.println("====== Performance Agent 启动 ======");
new AgentBuilder.Default()
// 指定要增强的类
.type(nameStartsWith("com.example.app"))
// 配置增强逻辑
.transform((builder, typeDescription, classLoader, module, protectionDomain) ->
builder.method(isPublic().and(not(isStatic())))
.intercept(MethodDelegation.to(PerformanceInterceptor.class))
)
// 安装到Instrumentation
.installOn(instrumentation);
System.out.println("====== Agent 安装完成 ======");
}
/**
* 性能监控拦截器
*/
public static class PerformanceInterceptor {
@RuntimeType
public static Object intercept(@SuperCall Callable<?> zuper,
@Origin String methodName,
@Origin Class<?> clazz) throws Exception {
long start = System.nanoTime();
try {
return zuper.call();
} finally {
long duration = (System.nanoTime() - start) / 1_000_000;
System.out.printf("[Agent] %s.%s 耗时: %dms%n",
clazz.getSimpleName(), methodName, duration);
}
}
}
}
MANIFEST.MF配置:
yaml
Manifest-Version: 1.0
Premain-Class: com.example.bytebuddy.agent.PerformanceAgent
Can-Redefine-Classes: true
Can-Retransform-Classes: true
7.2 动态Attach Agent
java
package com.example.bytebuddy.agent;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.*;
import java.util.concurrent.Callable;
import static net.bytebuddy.matcher.ElementMatchers.*;
/**
* 动态Attach Agent(无需重启JVM)
*/
public class DynamicAttachAgent {
public static class RuntimeInterceptor {
@RuntimeType
public static Object intercept(@SuperCall Callable<?> zuper,
@Origin String methodName) throws Exception {
System.out.println("[动态Agent] 拦截方法: " + methodName);
return zuper.call();
}
}
public static void attachAgent() {
// 动态安装Agent
ByteBuddyAgent.install();
new AgentBuilder.Default()
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.type(named("com.example.TargetClass"))
.transform((builder, typeDescription, classLoader, module, protectionDomain) ->
builder.method(any())
.intercept(MethodDelegation.to(RuntimeInterceptor.class))
)
.installOnByteBuddyAgent();
System.out.println("动态Agent已安装");
}
public static void main(String[] args) {
System.out.println("应用启动中...");
// 应用运行中动态安装Agent
attachAgent();
// 后续的类加载会被增强
}
}
八、最佳实践与注意事项
8.1 性能优化建议
java
// 1. 缓存动态生成的类
private static final ConcurrentHashMap<Class<?>, Class<?>> classCache =
new ConcurrentHashMap<>();
public static <T> Class<? extends T> getEnhancedClass(Class<T> clazz) {
return (Class<? extends T>) classCache.computeIfAbsent(clazz, key ->
new ByteBuddy()
.subclass(key)
.method(any())
.intercept(MethodDelegation.to(Interceptor.class))
.make()
.load(key.getClassLoader())
.getLoaded()
);
}
// 2. 使用@RuntimeType减少类型转换
@RuntimeType // 自动处理类型转换
public static Object intercept(@SuperCall Callable<?> zuper) {
return zuper.call();
}
// 3. 精确匹配,避免过度拦截
.method(named("specificMethod").and(takesArguments(2))) // ✓ 精确
.method(any()) // ✗ 拦截所有方法,性能差
8.2 常见陷阱
java
// 陷阱1: 循环依赖
public class BadInterceptor {
public static Object intercept() {
// 如果拦截的类中调用了这个方法,会导致无限递归
someMethod(); // ✗ 危险
return null;
}
}
// 陷阱2: 忘记调用原方法
public static Object intercept(@SuperCall Callable<?> zuper) {
// 忘记调用 zuper.call()
return null; // ✗ 原方法不会执行
}
// 陷阱3: 类加载器问题
Class<?> clazz = new ByteBuddy()
.subclass(Original.class)
.make()
.load(WrongClassLoader.class.getClassLoader()) // ✗ 错误的类加载器
.getLoaded();
九、总结
9.1 ElementMatcher使用指南
scss
ElementMatcher选择流程:
┌────────────────────────────────────────────┐
│ 需要匹配什么? │
├────────────────────────────────────────────┤
│ 类名 → named(), nameStartsWith() │
│ 方法名 → named(), nameMatches() │
│ 注解 → isAnnotatedWith() │
│ 修饰符 → isPublic(), isStatic() │
│ 返回值 → returns() │
│ 参数 → takesArguments() │
│ 继承关系 → isSubTypeOf() │
│ 组合条件 → and(), or(), not() │
└────────────────────────────────────────────┘
9.2 适用场景总结
| 场景 | 实现方式 | 难度 |
|---|---|---|
| 日志记录 | MethodDelegation | ★☆☆☆☆ |
| 性能监控 | MethodDelegation + 注解 | ★★☆☆☆ |
| 事务管理 | MethodDelegation + ThreadLocal | ★★★☆☆ |
| 数据库监控 | MethodDelegation + SQL解析 | ★★★☆☆ |
| Java Agent | AgentBuilder | ★★★★☆ |
| 类增强 | Subclass/Redefine | ★★★★☆ |
9.3 学习资源
- 官方文档 : bytebuddy.net/
- GitHub : github.com/raphw/byte-...
- 教程 : www.baeldung.com/byte-buddy
- 实战项目: SkyWalking、Arthas等APM工具
ByteBuddy作为现代化的字节码操作框架,通过ElementMatcher等高级API,让字节码增强变得简单而强大。掌握ElementMatcher的使用,是发挥ByteBuddy全部潜力的关键!