即使被调用一次,方法也会截获两次

问题描述:

在下面的代码片段中,我将调用方法doStuff一次在Subclass的实例上。但它被截获两次。即使被调用一次,方法也会截获两次

请注意,doStuff是在父类SuperClass中定义的。如果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; 
    } 
} 

您拦截方法调用每一个类型的,即两个SubclassSuperClass。您需要进一步指定拦截器拦截哪些方法。在你的情况下,你只想拦截方法,如果它们是由给定类型声明的。

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

最后,我可以看到,您的源代码中使用了旧版本的Byte Buddy。版本0.7-rc6运行稳定,具有附加功能并修复了一些错误。 (然而,一些API仍然需要改变。)

+0

这段代码运行在0.7-rc6上,但我仍然可能会使用一些旧的API。哦,顺便说一句,0.7-rc6的在线javadoc似乎打破了:http://bytebuddy.net/javadoc/0.7-rc6/index.html – user3408654

+1

Byte Buddy代理方法'ByteBuddyAgent.installOnOpenJDK()'应该是ByteBuddyAgent.install ),因为它支持J9和任何Java 9兼容平台。感谢提供给javadoc的提示,是一个命名问题。现在已经修复了。 –