ByteBuddy学习(1)

ByteBuddy是什么?

ByteBuddy 是一个功能强大的 Java 字节码操作库,主要用于在运行时动态生成和修改 Java 类。它提供了一种简单易用的 API,使得开发者无需直接操作复杂的字节码指令,即可实现动态代理、AOP(面向切面编程)、类增强等功能。 官网地址

快速使用

引入依赖

xml 复制代码
<dependency>
    <groupId>net.bytebuddy</groupId>
    <artifactId>byte-buddy</artifactId>
    <version>LATEST</version>
</dependency>

新建一个类

java 复制代码
public void helloWrold(){
    try {
        // 创建动态类
        Class<?> dynamicType = new ByteBuddy()
               .subclass(Object.class)
               .method(ElementMatchers.named("toString"))
               .intercept(FixedValue.value("Hello World"))
               .make()
               .load(ByteByddyTest.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
               .getLoaded();

        // 使用构造函数创建实例
        Constructor<?> constructor = dynamicType.getConstructor();
        Object instance = constructor.newInstance();

        // 调用 toString 方法
        String helloworld = instance.toString();
        System.out.println(helloworld);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
  • new ByteBuddy():创建一个 ByteBuddy 实例,作为构建动态类的起点。
  • .subclass(Object.class):指定要创建的动态类是 Object 类的子类。
  • .method(ElementMatchers.named("toString")):使用 ElementMatchers.named 方法匹配器选择 toString 方法,即要对这个方法进行拦截和修改。
  • .intercept(FixedValue.value("Hello World")):指定拦截逻辑,使用 FixedValue 让被拦截的 toString 方法重写,不使用默认的Object#toString方法,而是始终返回 "Hello World"字符串。
  • .make():根据前面的配置生成字节码。
  • .load(ByteBuddyExample.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER):使用当前类 ByteBuddyExample 的类加载器,并采用 ClassLoadingStrategy.Default.WRAPPER 策略将生成的字节码加载到 JVM 中。
  • .getLoaded():获取加载后的 Class 对象,存储在 dynamicType 变量中。
  • dynamicType.getConstructor():通过反射获取动态类的无参构造函数。
  • constructor.newInstance():调用构造函数创建动态类的一个新实例,存储在 instance 变量中。
  • instance.toString():调用动态类实例的 toString 方法,由于前面已经对该方法进行了拦截和重写,所以会返回 "Hello World"
  • System.out.println(helloworld):将 toString 方法的返回值打印到控制台

小测试

你可以将ElementMatchers.named("toString")中的toString 改为tostring,试试,会发现到最后就不能正常输出了,输入的是这个 原因是因为由于 ElementMatchers.named("tostring") 要匹配的就是'Object'类下面的'toString'方法,由于大小写不一致导致没有匹配到,但是 instance 变量的 toString() 方法没有被拦截,仍然会使用 Object 类的默认 toString() 实现,输出的是对象的哈希码字符串,而不是 "Hello World"

如果你不知道Object类的默认toString实现,没关系,实际上sout输出的一个对象的时候就会默认区调用这个对象的toString方法,而Object的默认toString方法是这样实现的

java 复制代码
public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

所以最后输出的是一个这样的格式的结果

嘻嘻,是不是还有点意思

相关推荐
ttwuai1 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
用户8356290780511 小时前
Python 实现 Excel 页面布局与打印设置自动化
后端·python
用户9931441579841 小时前
微服务框架中获取用户信息
后端
xuanWb1 小时前
手写一个 LLM API 网关:Anthropic 与 OpenAI 协议转换的完整实现
后端
苍何1 小时前
给 Codex 换皮肤这门生意,被我开源了
后端
用户8356290780511 小时前
Python 实现 Excel 命名范围(Named Range)的创建与管理
后端·python
程序员David2 小时前
我让 Claude 从架构文档一路干到代码,踩了三个坑才摸清边界
后端
Zane19942 小时前
并发 vs 并行:别再傻傻分不清了,一文讲透 Java 并发编程的第一课
java·后端
神奇小汤圆2 小时前
线程池拒绝策略CallerRunsPolicy反而卡死了主线程
后端