【问题标题】:Inspect CGLib proxied Groovy classes from Java从 Java 检查 CGLib 代理的 Groovy 类
【发布时间】:2013-08-16 22:39:44
【问题描述】:

我正在尝试检查一些来自 Java 的 CGLib 代理 Groovy 类上的 Groovy 生成的方法,以了解方法的返回和参数类型。例如,考虑这个 Groovy 类:

class Person {
  String name
}

Groovy 为 name 属性生成 getName()setName() 方法。 getName() 大概返回一个 StringsetName() 大概需要一个 String

但是当通过 CGLib 代理此类并使用 CGLib 的 MethodInterceptor 拦截对 getName 的调用时,method.getName() 返回 getMetaClassmethod.getReturnType() 返回 groovy.lang.MetaClass

有没有办法从MethodInterceptor 中了解实际的方法名称和返回类型?

编辑:这是拦截 Person.getName() 调用时的调用堆栈:

ExplicitMappingInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 42    
GroovyMMTester$A$$EnhancerByCGLIB$$915b5b4.getMetaClass() line: not available   
CallSiteArray.createPogoSite(CallSite, Object, Object[]) line: 144  
CallSiteArray.createCallSite(CallSite, Object, Object[]) line: 161  
CallSiteArray.defaultCall(CallSite, Object, Object[]) line: 45  
AbstractCallSite.call(Object, Object[]) line: 108   
AbstractCallSite.call(Object) line: 112 
GroovyMMTester$Map.configure() line: 18 <-- Person.getName() call is in here, but doesn't show

【问题讨论】:

  • 使用CGLib而不是Metaclass的原因是什么?
  • 我猜你调用的是 Person 对象上的 getName(),而不是直接 Person.getName()。对吗?

标签: java reflection groovy proxy-classes cglib


【解决方案1】:

我认为你遇到的问题基本上是你有调用方法的Java思维会直接调用方法并完成它。好吧,甚至 Java 也没有这样做,但这些东西隐藏在 JVM 中。 Groovy 没有修改 JVM 的奢侈,因此可能会在调用最终方法之前调用一组方法。由于这是一个实现细节,因此顺序可能会有所不同。由于 Groovy 是一种具有运行时元编程的语言,因此您期望的目标方法可能根本不会被调用。

无论如何,为了能够在 Groovy 中调用 getName() 方法,Groovy 运行时首先必须获取调用对象的元类,这会导致调用 getMetaClass()。如果您在此处拦截,那么您可能永远无法获得所需的方法调用。

解决方案实际上很简单……您只需过滤那些辅助方法。那将是任何以 $ 开头的方法和任何以 this$ 开头的方法,以及 super$ 和 getMetaClass 方法。过滤意味着在这里你不拦截,而只是使用反射继续调用。如果您遇到了一种不在该集合中的方法,那么您很可能拥有目标。在您的示例中,method.getName() 将返回“getName”。

【讨论】:

    【解决方案2】:

    请检查/共享您用于调用 getName() 方法的代码,因为有时在请求 groovy 对象的属性时,它使用 getPropertygetAttribute 方法,它们都调用 getStaticMetaClass()方法,我认为这是实际发生在你身上的事情。

    我的意思是,实际上不是直接调用getNamePerson 对象,而是调用getProperty(..., personObject, 'name', ...) 方法,该方法调用getStaticMetaClass().getProperty(..., personObject, 'name', ...)

    您还可以尝试调试代码,例如在调用 method.getName() 的行上放置断点,并查看堆栈跟踪如何调用 getName() 方法。

    【讨论】:

    • OP 想知道在 Java 中使用反射的返回类型。 :)
    • 我正在使用 CGLib 来代理类,并使用 CGLib 的 MethodInterceptor 来拦截针对 getName/setName 的调用。这是我希望学习“属性类型”的起点。不幸的是,由于method.getName() 返回$getStaticMetaClass,因此拦截器似乎没有办法了解方法的名称。
    • 没有转储一堆代码,我基本上只是使用CGLib的Enhancer类创建代理并传入一个MethodInterceptor作为回调)。因此,当调用 MethodInterceptor 的拦截方法时,我试图确定被拦截的 Groovy 方法的名称和返回类型。我会尝试获取更多调试输出...
    • 那么,如果您正在做类似 cglib 示例中的操作,然后直接调用 getName(),我很确定正在发生的事情就是我在回答中提出的内容。
    • 使用调用堆栈更新了 OP。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-30
    • 1970-01-01
    相关资源
    最近更新 更多