Java 当我想要截取一个方法时,我可以只使用接口来创建子类吗?

Java 当我想要截取一个方法时,我可以只使用接口来创建子类吗?,java,aop,byte-buddy,Java,Aop,Byte Buddy,我试图使用byte buddy拦截方法,但发现它仅在您子类型接口时才起作用 下面的代码片段演示了这一点,您可以看到“hello”被传递到3种类型的相同“message”方法中,但只截获接口子类型 import net.bytebuddy.ByteBuddy; import net.bytebuddy.implementation.MethodDelegation; import net.bytebuddy.implementation.attribute.AnnotationRetention;

我试图使用byte buddy拦截方法,但发现它仅在您子类型接口时才起作用

下面的代码片段演示了这一点,您可以看到“hello”被传递到3种类型的相同“message”方法中,但只截获接口子类型

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.attribute.AnnotationRetention;
import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Morph;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.This;
import net.bytebuddy.matcher.ElementMatchers;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;

class Sandbox {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        testIt(StaticClass.class).message("hello");
        testIt(AbstractStaticClass.class).message("hello");
        testIt(Interface.class).message("hello");
    }

    private static <T> T testIt(Class<T> aClass) throws IllegalAccessException, InstantiationException {
        return new ByteBuddy().with(AnnotationRetention.ENABLED)
            .subclass(aClass)
            .method(
                    ElementMatchers.isAnnotatedWith(AnAnnotation.class)
            ).intercept(
                    MethodDelegation.withDefaultConfiguration()
                        .withBinders(Morph.Binder.install(Invoker.class))
                        .to(new Interceptor()))
            .make()
            .load(Sandbox.class.getClassLoader())
            .getLoaded()
            .newInstance();
    }

    public interface Invoker {
        Object invoke(Object[] args);
    }

    public static class Interceptor {
    @RuntimeType
    public Object intercept(@This Object proxy, @Origin Method method, @Morph(defaultMethod = true) Invoker invoker, @AllArguments Object[] args) {
            return invoker.invoke(new Object[]{"there"});
        }
    }

    public static class StaticClass {
        @AnAnnotation
        String message(String message) {
            System.out.println(getClass().getName() + ": message: " + message);
            return message;
        }
    }

    public static abstract class AbstractStaticClass {
        @AnAnnotation
        String message(String message) {
            System.out.println(getClass().getName() + ": message: " + message);
            return message;
        }
    }

    public interface Interface {
        @AnAnnotation
        default String message(String message) {
            System.out.println(getClass().getName() + ": message: " + message);
            return message;
        }
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    private @interface AnAnnotation {}
}
如何拦截类的方法以及接口的方法


谢谢

您正在定义仅在包中可见的包私有方法。您还使用默认的类注入策略,该策略将创建一个新的类加载器来加载注入的类。在运行时,两个包只有在名称和类加载器相同(类似于类)时才相等

<>实际上,Byte Buddy为类创建了方法,因为类创建不考虑目标类加载器。您可以通过对生成的类调用
getDeclaredMethod
并调用它们来验证这一点。然而,Java实际上不会分派这种包外部方法,即使它们具有相同的签名。要在同一类加载器中定义类,可以使用
ClassLoadingStrategy.Default.INJECTION
。但是请注意,不鼓励使用此策略,因为它依赖于不安全的API。在Java 9+中,您可以使用
ClassLoadingStrategy.UsingLookup
来代替安全性


当然,您也可以将方法更改为公共的或受保护的。

感谢Rafael,我还必须将@morp注释上的defaultMethod属性更改为false,才能使我的类正常工作。现在一切都好了,伟大的自由顺便说一句:)
public static class StaticClass extends AbstractStaticClass { ... }
public static abstract class AbstractStaticClass implements Interface { ... }
public interface Interface { ... }