Java 如何拦截构造函数
我想截取所有用@Inject注释的方法。下面的测试表明,它可以很好地处理方法,但不能处理构造函数。我错过了什么 我试图添加一个定制的方法匹配器,但我注意到从来没有给我一个与构造函数对应的MethodDescriptionJava 如何拦截构造函数,java,bytecode,byte-buddy,Java,Bytecode,Byte Buddy,我想截取所有用@Inject注释的方法。下面的测试表明,它可以很好地处理方法,但不能处理构造函数。我错过了什么 我试图添加一个定制的方法匹配器,但我注意到从来没有给我一个与构造函数对应的MethodDescription public class InterceptConstructorTest { @Test public void testConstructorInterception() { ByteBuddyAgent.install();
public class InterceptConstructorTest {
@Test
public void testConstructorInterception() {
ByteBuddyAgent.install();
new AgentBuilder.Default().type(nameStartsWith("test")).transform(new AgentBuilder.Transformer() {
@Override
public Builder<?> transform(Builder<?> builder, TypeDescription td) {
return builder.method(isAnnotatedWith(Inject.class))
.intercept(MethodDelegation.to(MethodInterceptor.class).andThen(SuperMethodCall.INSTANCE));
}
}).installOnByteBuddyAgent();
// Call constructor => NOT intercepted
MyClass myClass = new MyClass("a param");
// Call method => intercepted
myClass.aMethod("a param");
}
}
class MyClass {
@Inject
public MyClass(String aParam) {
System.out.println("constructor called");
}
@Inject
public void aMethod(String aParam) {
System.out.println("aMethod called");
}
}
class MethodInterceptor {
public static void intercept(@Origin Method method) {
System.out.println("Intercepted: " + method.getName());
}
}
您明确指定只希望拦截方法:
builder.method(isAnnotatedWith(Inject.class))
您也可以这样做:
builder.constructor(isAnnotatedWith(Inject.class))
甚至:
builder.invokeable(isAnnotatedWith(Inject.class))
然而,这里有一个陷阱。任何构造函数都必须从被拦截的构造函数中调用另一个构造函数。在您的情况下,这已经通过使用SuperMethodCall.INSTANCE
给出,您的代码将运行。但是,请注意某些构造对构造函数不可用,例如,在调用超级构造函数之前,不能插入@This
引用。如果合适,您可以切换以下选项:
MethodDelegation.to(MethodInterceptor.class)
.andThen(SuperMethodCall.INSTANCE)
成为
SuperMethodCall.INSTANCE
.andThen(MethodDelegation.to(MethodInterceptor.class))
当使用这种排序时,JVM不再抱怨是否插入了被拦截实例的属性
最后,确保提供适当的拦截:
class MethodInterceptor {
public static void intercept(@Origin Method method) {
System.out.println("Intercepted: " + method.getName());
}
public static void intercept(@Origin Constructor<?> constructor) {
System.out.println("Intercepted: " + constructor.getName());
}
}
类方法拦截器{
公共静态无效截距(@Origin方法){
System.out.println(“截获:“+method.getName());
}
公共静态无效截获(@Origin构造函数){
System.out.println(“截获:“+constructor.getName());
}
}
否则,Byte Buddy无法将
构造函数
引用绑定到方法
并放弃绑定该方法(从0.7.6开始,以前存在一个导致验证器错误的错误)。在使用Java 8时,还可以使用可执行文件
类型提供一个拦截器。我用“构造函数”尝试了这两种方法和“invokable”,我得到了以下异常(版本0.7.5):您正在使用@Origin和一个应该使用构造函数的方法类型。Buddy应该会注意到,这是一个bug。您需要使用构造函数作为拦截器的类型。哦,对了,谢谢!现在我更好地理解了异常消息。我不知道反射API区分了构造函数和方法。在构建器上使用方法/构造函数/可调用也更有意义。我将修复它,明天早上推出新版本。
class MethodInterceptor {
public static void intercept(@Origin Method method) {
System.out.println("Intercepted: " + method.getName());
}
public static void intercept(@Origin Constructor<?> constructor) {
System.out.println("Intercepted: " + constructor.getName());
}
}