ByteBuddy 实战指南

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作为现代化的字节码操作框架,通过ElementMatcher等高级API,让字节码增强变得简单而强大。掌握ElementMatcher的使用,是发挥ByteBuddy全部潜力的关键!


相关推荐
Apifox36 分钟前
Apifox 11 月更新|AI 生成测试用例能力持续升级、JSON Body 自动补全、支持为响应组件添加描述和 Header
前端·后端·测试
有风631 小时前
双向循环带头链表详解
后端
找不到对象就NEW一个1 小时前
用wechatapi进行微信二次开发,微信api
后端
charlie1145141911 小时前
勇闯前后端Week2:后端基础——Flask API速览
笔记·后端·python·学习·flask·教程
有风631 小时前
基于顺序表完成通讯录项目
后端
yuuki2332331 小时前
【C++】初识C++基础
c语言·c++·后端
q***87601 小时前
springboot下使用druid-spring-boot-starter
java·spring boot·后端
程序员西西1 小时前
SpringBoot无感刷新Token实战指南
java·开发语言·前端·后端·计算机·程序员
南雨北斗1 小时前
mysql视图的作用
后端