我尝试使用 Byte Buddy 0.7.1 拦截对混合 Java (8) 和 Groovy (2.4.5) 项目中的类方法的调用。
这个想法是为特定包(如 foo
)中的类的方法调用及其参数创建一个类似“通用日志记录飞行记录器”的东西。
我使用 Byte Buddy AgentBuilder
和我的自定义 LogInterceptor
在应用程序启动时执行此操作:
static {
final Instrumentation inst = ByteBuddyAgent.install();
new AgentBuilder.Default()
.type(ElementMatchers.nameContainsIgnoreCase("foo")) // simplified
.transform((builder, typeDescription) ->
builder.method(ElementMatchers.any())
.intercept(MethodDelegation.to(LogInterceptor.class)
.andThen(SuperMethodCall.INSTANCE)))
.installOn(inst);
}
public static class LogInterceptor {
@RuntimeType
public static void log(@Origin Method method, @AllArguments Object[] arg) throws Exception {
// flightRecorder.log(...);
}
}
方法拦截对所有 Java 类都适用。它适用于所有带有 @CompileStatic 注释的 Groovy 类。
但是对于具有奇怪的 java.lang.VerifyError
之类的经典(动态)Groovy 类,它会失败
java.lang.VerifyError: (class: foo/MyInterceptedClass$barMethod, method: <clinit> signature: ()V) Illegal type in constant pool
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
at java.lang.Class.getConstructor0(Class.java:3075)
at java.lang.Class.getConstructor(Class.java:1825)
at org.codehaus.groovy.reflection.ClassLoaderForClassArtifacts.defineClassAndGetConstructor(ClassLoaderForClassArtifacts.java:83)
at org.codehaus.groovy.runtime.callsite.CallSiteGenerator.compileStaticMethod(CallSiteGenerator.java:246)
at org.codehaus.groovy.reflection.CachedMethod.createStaticMetaMethodSite(CachedMethod.java:288)
at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite.createStaticMetaMethodSite(StaticMetaMethodSite.java:114)
at groovy.lang.MetaClassImpl.createStaticSite(MetaClassImpl.java:3385)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallStaticSite(CallSiteArray.java:77)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallSite(CallSiteArray.java:162)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133)
...
这是怎么回事? Byte Buddy支持Groovy方法拦截吗?
最佳答案
由于我不知道的原因,Groovy 生成类级别 1.4 的类,其中 Byte Buddy 生成的某些字节代码构造是不合法的。这会生成一个VerifyError
。在使用 Byte Buddy 时,这当然不是一个非常有建设性的错误消息,这就是为什么 Byte Buddy 应用的类 validator 现在会检查 Java 字节码 1.4 中是否非法使用现代概念。 p>
为了克服这一限制,Byte Buddy 0.7.2(今天发布)包含一个 ClassVisitorWrapper
,它修复了注册时由兼容的旧指令表示的现代字节代码添加的TypeConstantAdjustment
。此调整并不完美,因为如果缺少类,则会导致 ClassNotFoundException
,而 JLS 通常需要 NoClassDefFoundError
。如果您可以忍受这个限制,那么就可以保存使用。该调整会自行发现是否需要(Java 4 或更早版本),因此如果需要,您可以简单地添加它。
关于java - 使用 Byte Buddy 拦截对我的 Java 和 Groovy 代码的方法调用 : Strange java. lang.VerifyError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33942856/