【问题标题】:Method intercepted twice even though it was called once方法被拦截了两次,即使它被调用了一次
【发布时间】:2015-11-01 17:12:17
【问题描述】:

在下面的代码 sn-p 中,我在 Subclass 的实例上调用了一次方法 doStuff。但是它被拦截了两次。

请注意,doStuff 是在父类 SuperClass 中定义的。如果在SubClass 中定义了doStuff,则拦截逻辑将按预期工作:只有一次拦截。

我是否错误地使用了 Byte Buddy?

package com.test;

import static net.bytebuddy.matcher.ElementMatchers.any;
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;

import java.util.concurrent.Callable;

import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType.Builder;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;

import org.junit.Test;

public class ReproBugTest {

    @Test
    public void reproBug() {

        new AgentBuilder.Default().type(nameStartsWith("com.test"))
                                    .transform(new AgentBuilder.Transformer() {

                                        @Override
                                        public Builder<?> transform(
                                                Builder<?> builder,
                                                TypeDescription td) {

                                            return builder.method(any())
                                                            .intercept(
                                                                    MethodDelegation.to(MethodInterceptor.class));
                                        }
                                    })
                                    .installOn(
                                            ByteBuddyAgent.installOnOpenJDK());

        SubClass subClass = new SubClass();
        subClass.doStuff();
    }
}

class SuperClass {
    public void doStuff() {
        System.out.println("Doing stuff...");
    }
}

class SubClass extends SuperClass {
}

class MethodInterceptor {

    @RuntimeType
    public static Object intercept(@SuperCall Callable<?> zuper)
            throws Exception {

        // Intercepted twice, bug?
        System.out.println("Intercepted");

        Object returnValue = zuper.call();

        return returnValue;
    }
}

【问题讨论】:

    标签: java bytecode agent byte-buddy


    【解决方案1】:

    您正在拦截每种类型的方法调用,即SubclassSuperClass。您需要进一步指定拦截器以拦截哪些方法。在您的情况下,您只想拦截由给定类型声明的方法。

    这很容易实现。你应该拦截builder.method(isDeclaredBy(td)),而不是builder.method(any())。这样,一个方法只有在被拦截类型声明时才会被拦截。

    最后,我可以从您的源代码中看到您使用的是旧版本的 Byte Buddy。版本 0.7-rc6 运行稳定,具有附加功能并修复了几个错误。 (不过,部分 API 仍需更改。)

    【讨论】:

    • 这个 sn-p 在 0.7-rc6 上运行,但我可能仍在使用一些旧的 API。哦,顺便说一句,0.7-rc6 的在线 javadoc 似乎坏了:bytebuddy.net/javadoc/0.7-rc6/index.html
    • Byte Buddy 代理方法ByteBuddyAgent.installOnOpenJDK() 应该是ByteBuddyAgent.install(),因为它支持J9 和任何Java 9 兼容平台。感谢您对 javadoc 的提示,这是一个命名问题。现在已经修好了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多