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());
}

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

嘻嘻,是不是还有点意思

相关推荐
uzong2 小时前
技术故障复盘模版
后端
GetcharZp2 小时前
基于 Dify + 通义千问的多模态大模型 搭建发票识别 Agent
后端·llm·agent
桦说编程2 小时前
Java 中如何创建不可变类型
java·后端·函数式编程
IT毕设实战小研2 小时前
基于Spring Boot 4s店车辆管理系统 租车管理系统 停车位管理系统 智慧车辆管理系统
java·开发语言·spring boot·后端·spring·毕业设计·课程设计
wyiyiyi3 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
阿华的代码王国4 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
Jimmy4 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
AntBlack4 小时前
不当韭菜V1.1 :增强能力 ,辅助构建自己的交易规则
后端·python·pyqt
bobz9655 小时前
pip install 已经不再安全
后端
寻月隐君5 小时前
硬核实战:从零到一,用 Rust 和 Axum 构建高性能聊天服务后端
后端·rust·github