【问题标题】:Intercept all methods/construtors/getters/setters from a specific namespace拦截来自特定命名空间的所有方法/构造器/getter/setter
【发布时间】:2016-07-22 10:19:11
【问题描述】:

我有一个这样实现的 Java 代理:

public static void premain(String args, Instrumentation instrumentation) throws ClassNotFoundException {
    new AgentBuilder.Default()
      .type(isSubTypeOf(Object.class).and(nameStartsWith("com.my.domain")))
      .transform(new Transformer5())
      .installOn(instrumentation);
}

然后是Transform类:

public class Transformer5 implements AgentBuilder.Transformer {
    public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader) {
        return builder.method(any().and(isDeclaredBy(typeDescription)))
                      .intercept(MethodDelegation.to(Interc4.class));
    }
}

和一个拦截器:

public class Interc4 {

    static String indent = "";

    @RuntimeType
    @BindingPriority(BindingPriority.DEFAULT * 3)
    public static Object intercept(@SuperCall Callable<?> zuper, 
                                   @AllArguments Object[] allArguments, 
                                   @Origin String method) throws Exception {

        System.out.println(indent + "Intercepted4 M" + method);

        try {
            indent += "  ";
            return zuper.call();
        } finally {
            //post process
            indent = indent.substring(0, indent.length()-2);
        }

    }

}

这样做的问题是它不拦截构造函数,它也给出了这种错误

不能为接口类型定义非公共或非虚拟方法'lambda$static$1'

制作从某个域代理类中的每个方法的拦截器的最佳方法是什么(我希望能够获取方法名称、检查方法参数(如果有的话)并转发执行)。

【问题讨论】:

    标签: java code-generation bytecode instrumentation byte-buddy


    【解决方案1】:

    发生这种情况有两个原因。

    1. Cannot define non-public or non-virtual method 'lambda$static$1' for interface type 是由 Byte Buddy 中的验证错误引起的。我将在下一个版本中解决这个问题。同时,您可以通过new AgentBuilder.Default(new ByteBuddy().with(TypeValidation.DISABLED))禁用验证。

    2. 您只能通过.method( ... ) 匹配来显式拦截方法。您可以通过.constructor( ... ).invokable( ... ) 拦截任何可调用的构造函数。但是,您将无法将拦截器用于必须对超级方法调用进行硬编码的构造函数。但是,您可以将拦截器分成两部分:

      class Interceptor {
        public static void before() { ... }
        public static void after() { ... }
      }
      

      使用

      .intercept(MethodDelegation.to(Interceptor.class).filter(named("before")
         .andThen(SuperMethodCall.INSTANCE
         .andThen(MethodDelegation.to(Interceptor.class).filter(named("after"))))
      

    这样,Byte Buddy 可以硬编码超级构造函数调用,同时触发beforeafter 方法。请注意,@This 注释不适用于 before 方法。

    【讨论】:

      猜你喜欢
      • 2018-12-27
      • 2012-02-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-26
      相关资源
      最近更新 更多