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());
}
所以最后输出的是一个这样的格式的结果
嘻嘻,是不是还有点意思