首页 > 解决方案 > 关于如何正确有效地使用 ByteBuddy 的指南

问题描述

我查看了 ByteBuddy 文档,还查看了一些使用 ByteBuddy 的 Java 代理实现。但是我仍然不太清楚什么是使用 ByteBuddy 代理的正确方法。

这是我用来引导代理的代码:

public class ByteBuddyAgent {

    public static void premain(String arguments, Instrumentation instrumentation) {

        System.out.println("Bootstrapping ByteBuddy Agent");


        new AgentBuilder.Default()
                .with(new AgentBuilder.InitializationStrategy.SelfInjection.Eager())
                .type(ElementMatchers.hasSuperClass(ElementMatchers.nameContains("Level1")))
                .transform(new ByteBuddyTransformer()
                .installOn(instrumentation);

    }

    private static class ByteBuddyTransformer implements AgentBuilder.Transformer{

        @Override
        public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription,
                                                ClassLoader classLoader, JavaModule module) {

            return builder.method(ElementMatchers.named("printLevel"))
                    .intercept(Advice.to(MethodTracker.class));
        }
    }
}

这是我的 Advice 课程,我在其中尝试了 Advice 支持的不同注释,并且效果很好。

public class MethodTracker {

    @Advice.OnMethodEnter
    public static Object onMethodBegin(@Advice.This Object invokedObject, @Advice.AllArguments Object[] arguments,
                                       @Advice.FieldValue("name") Object fieldValue, @Advice.Origin Object origin,
                                       @Advice.Local("localVariable") Object localVariable) {
        System.out.println("=======on Method Begin Running with ByteBuddy=======, " + invokedObject);
        System.out.println("======Printing arguments=======");
        for(Object obj: arguments){
            System.out.println("Argument:: " + obj);
        }
        localVariable = "Gunika";

        System.out.println("FieldValue:: " + fieldValue);
        System.out.println("Origin:: " + origin);
        return "ReturningStateFromOnMethodBegin";
    }

    @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
    public static void onMethodEnd(@Advice.This Object invokedObject, @Advice.Return Object returnValue,
                                   @Advice.FieldValue("name") Object fieldValue, @Advice.Enter Object state,
                                   @Advice.Local("localVariable") Object localVariable){
        System.out.println("=======on Method End Running with ByteBuddy======= " + invokedObject);

        System.out.println("Return value is " + returnValue);
        System.out.println("FieldValue:: " + fieldValue);
        System.out.println("FieldValue:: " + fieldValue);
        System.out.println("State:: " + state);
        System.out.println("LocalVariable:: " + localVariable);
    }
}

我的问题如下:

标签: bytecodeinstrumentationbyte-buddy

解决方案


Advice.to(MethodTracker.class)很贵。如果您检测许多类并想消耗内存,我建议您重用该实例,它是不可变的。

除此之外@Advice.AllArguments,如果您负担得起的话,它比使用读取特定参数的专门建议类更昂贵。然而,这是一个 JVM 问题,而不是 Byte Buddy 特定的问题。您可以使用-Dnet.bytebuddy.dump=/some/folder查看生成的字节码。昂贵的东西往往掩盖了你想要的结构。


推荐阅读