ByteBuddy 是 JavaAgent的一种实现,他的性能比较好,api使用起来也比较方便
本文主要简单介绍如何使用ByteBuddy操作字节码
首先引入依赖
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
</dependency>
上代码
先来看一个方法匹配拦截的例子
@Slf4j
public class ByteBuddyTest {
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
Class<?> loadType = new ByteBuddy()
.subclass(Object.class)
.method(ElementMatchers.named("toString")) // 需要拦截的方法
.intercept(FixedValue.value("hello world")) //拦截做的事情->FixedValue固定值返回
.make() // 产生字节码
.load(ByteBuddyTest.class.getClassLoader()) // 加载类
.getLoaded(); // 获得class对象
String result = loadType.newInstance().toString();
log.info("result:{}", result);
}
}
上述代码就可以做到修改字节码,让toString()方法固定返回 “hello world”
.method 就是指定需要拦截的方法
.intercept 就是拦截要做的事情
.make 就是产生字节码
.load 就是加载类
.getLoaded 就是获得class对象
再来个例子:
@Slf4j
public class Foo {
public String aha() { return null; }
public String foo() { return null; }
public String foo(String str) { return null; }
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
Foo foo = new ByteBuddy()
.subclass(Foo.class)
.method(isDeclaredBy(Foo.class))
.intercept(FixedValue.value("all method"))
.method(ElementMatchers.named("foo"))
.intercept(FixedValue.value("foo call"))
.method(ElementMatchers.named("foo").and(ElementMatchers.takesArguments(1)))
.intercept(FixedValue.value("foo call 1 arg"))
.make()
.load(Foo.class.getClassLoader())
.getLoaded()
.newInstance();
log.info(foo.aha());
log.info(foo.foo());
log.info(foo.foo("nima"));
}
}
输出:
all method
foo call
foo call 1 arg
还有一个用法,方法委托
public class Source {
public String hello(String name) {
return name;
}
}
public class Target {
// FIXME: 这个为啥必须得加 static
public static String hello(String name) {
return "hello, " + name;
}
}
public class DelegationTest {
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
// 委托方法
String delegationResult = new ByteBuddy()
.subclass(Source.class)
.method(ElementMatchers.named("hello"))
.intercept(MethodDelegation.to(Target.class))
.make()
.load(DelegationTest.class.getClassLoader())
.getLoaded()
.newInstance()
.hello("wmx");
System.out.println(delegationResult);
}
}
通过 MethodDelegation 生成代理,代码结果输出 hello, wmx
再来一个基于注解的拦截,实现类似 aop aspect 的功能 =-=
public class Foo {
public String aha() {
System.out.println("doing ...");
return "aha";
}
整个拦截器
public class LogInterceptor {
@RuntimeType
public Object intercept(
@This Object target,
@Origin Method method,
@AllArguments Object[] args,
@Super Object delegate,
@SuperCall Callable<?> callable) throws Exception {
System.out.println("before ... method = " + method.getName());
// 和Spring AOP 中的 ProceedingJoinPoint.proceed() 好像
Object result = callable.call();
System.out.println("after ... method = " + method.getName());
return result;
}
}
public class InterceptorTest {
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
Foo foo = new ByteBuddy()
.subclass(Foo.class)
.method(isDeclaredBy(Foo.class))
.intercept(MethodDelegation.to(new LogInterceptor()))
.make()
.load(InterceptorTest.class.getClassLoader())
.getLoaded()
.newInstance();
String result = foo.aha();
System.out.println(result);
}
}
代码结果输出:
before … method = aha
doing …
after … method = aha
result
ok,有了前面几个例子,我们已经初步学习了ByteBuddy的使用!
转载请注明:汪明鑫的个人博客 » 使用 ByteBuddy 操作字节码
说点什么
您将是第一位评论人!