使用 byte buddy API 打印方法参数
Prtining method arguments using byte buddy API
我正在做一个项目,在执行期间我需要访问方法参数。
是否可以使用字节伙伴框架打印方法参数?非常感谢使用 javaagent 的任何示例代码。
是的,这是可能的。您可以使用 MethodDelegation
或 Advice
注入代码,然后使用 @AllArguments
注释获取实际参数。
问题是,您如何在项目中创建代码?您可以将 Java 代理与 AgentBuilder
一起使用,或者使用 ByteBuddy
实例创建代理子 类。请参阅文档和提到的 类 javadoc 以了解这是如何完成的。
这是一个如何使用 MethodDelegation
实现的示例。我用它来衡量方法的执行时间。我特地没有开始删除多余的代码,因为我想更充分地揭示Byte Buddy
.
的能力
package md.leonis.shingler;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import net.bytebuddy.matcher.ElementMatchers;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
public class MeasureMethodTest {
public static void main(String[] args) throws InterruptedException {
premain(ByteBuddyAgent.install());
for (int i = 0; i < 4; i++) {
SampleClass.foo("arg" + i);
}
}
public static void premain(Instrumentation instrumentation) {
new AgentBuilder.Default()
.type(ElementMatchers.nameStartsWith("md.leonis.shingler"))
.transform((builder, type, classLoader, module) ->
builder.method(ElementMatchers.any()).intercept(MethodDelegation.to(AccessInterceptor.class))
).installOn(instrumentation);
}
public static class AccessInterceptor {
@RuntimeType
public static Object intercept(@Origin Method method, @SuperCall Callable<?> callable, @AllArguments Object[] args) throws Exception {
long start = System.nanoTime();
try {
return callable.call();
} finally {
if (method.getAnnotationsByType(Measured.class).length > 0) {
String params = Arrays.stream(args).map(Object::toString).collect(Collectors.joining(", "));
System.out.println(method.getReturnType().getSimpleName() + " " + method.getName() + "("+ params +") took " + ((System.nanoTime() - start) / 1000000) + " ms");
}
}
}
}
public static class SampleClass {
@Measured
static void foo(String s) throws InterruptedException {
Thread.sleep(50);
}
}
}
此示例测量在 md.leonis.shingler
包中找到并标有 @Measured
注释的所有方法的执行时间。
要运行它,你需要两个库:byte-buddy and byte-buddy-agent.
工作成果:
void foo(arg0) took 95 ms
void foo(arg1) took 50 ms
void foo(arg2) took 50 ms
void foo(arg3) took 50 ms
请注意,控制台显示传递给该方法的所有参数的值。这是对问题的回答。
注释示例如下:
package md.leonis.shingler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Measured {
}
老实说,我无法直接在代理中配置注解过滤。这是一个示例(不起作用):
new AgentBuilder.Default()
.type(ElementMatchers.isAnnotatedWith(Measured.class))
.transform((builder, type, classLoader, module) ->
builder.method(ElementMatchers.any()).intercept(MethodDelegation.to(AccessInterceptor.class))
).installOn(instrumentation);
如果有人知道怎么做,请在下面评论。
我正在做一个项目,在执行期间我需要访问方法参数。 是否可以使用字节伙伴框架打印方法参数?非常感谢使用 javaagent 的任何示例代码。
是的,这是可能的。您可以使用 MethodDelegation
或 Advice
注入代码,然后使用 @AllArguments
注释获取实际参数。
问题是,您如何在项目中创建代码?您可以将 Java 代理与 AgentBuilder
一起使用,或者使用 ByteBuddy
实例创建代理子 类。请参阅文档和提到的 类 javadoc 以了解这是如何完成的。
这是一个如何使用 MethodDelegation
实现的示例。我用它来衡量方法的执行时间。我特地没有开始删除多余的代码,因为我想更充分地揭示Byte Buddy
.
package md.leonis.shingler;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import net.bytebuddy.matcher.ElementMatchers;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
public class MeasureMethodTest {
public static void main(String[] args) throws InterruptedException {
premain(ByteBuddyAgent.install());
for (int i = 0; i < 4; i++) {
SampleClass.foo("arg" + i);
}
}
public static void premain(Instrumentation instrumentation) {
new AgentBuilder.Default()
.type(ElementMatchers.nameStartsWith("md.leonis.shingler"))
.transform((builder, type, classLoader, module) ->
builder.method(ElementMatchers.any()).intercept(MethodDelegation.to(AccessInterceptor.class))
).installOn(instrumentation);
}
public static class AccessInterceptor {
@RuntimeType
public static Object intercept(@Origin Method method, @SuperCall Callable<?> callable, @AllArguments Object[] args) throws Exception {
long start = System.nanoTime();
try {
return callable.call();
} finally {
if (method.getAnnotationsByType(Measured.class).length > 0) {
String params = Arrays.stream(args).map(Object::toString).collect(Collectors.joining(", "));
System.out.println(method.getReturnType().getSimpleName() + " " + method.getName() + "("+ params +") took " + ((System.nanoTime() - start) / 1000000) + " ms");
}
}
}
}
public static class SampleClass {
@Measured
static void foo(String s) throws InterruptedException {
Thread.sleep(50);
}
}
}
此示例测量在 md.leonis.shingler
包中找到并标有 @Measured
注释的所有方法的执行时间。
要运行它,你需要两个库:byte-buddy and byte-buddy-agent.
工作成果:
void foo(arg0) took 95 ms
void foo(arg1) took 50 ms
void foo(arg2) took 50 ms
void foo(arg3) took 50 ms
请注意,控制台显示传递给该方法的所有参数的值。这是对问题的回答。
注释示例如下:
package md.leonis.shingler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Measured {
}
老实说,我无法直接在代理中配置注解过滤。这是一个示例(不起作用):
new AgentBuilder.Default()
.type(ElementMatchers.isAnnotatedWith(Measured.class))
.transform((builder, type, classLoader, module) ->
builder.method(ElementMatchers.any()).intercept(MethodDelegation.to(AccessInterceptor.class))
).installOn(instrumentation);
如果有人知道怎么做,请在下面评论。