Groovy-ProxyMetaClass的拦截器不影响内部方法调用

Groovy-ProxyMetaClass的拦截器不影响内部方法调用,groovy,interceptor,metaclass,Groovy,Interceptor,Metaclass,代码片段来自《Groovy in action 2nd》一书,稍作修改 1此代码按预期工作 package test class InspectMe { int outer(){ return inner() } int inner(){ return 1 } } def tracer = new TracingInterceptor(writer: new StringWriter()) def proxyMetaClass

代码片段来自《Groovy in action 2nd》一书,稍作修改

1此代码按预期工作

package test

class InspectMe {
    int outer(){
        return inner()
    }
    int inner(){
        return 1
    }
}

def tracer = new TracingInterceptor(writer: new StringWriter())
def proxyMetaClass = ProxyMetaClass.getInstance(InspectMe)
proxyMetaClass.interceptor = tracer
InspectMe inspectMe = new InspectMe()

inspectMe.metaClass = proxyMetaClass
inspectMe.outer()
println(tracer.writer.toString())
输出:

before test.InspectMe.outer()
  before test.InspectMe.inner()
  after  test.InspectMe.inner()
after  test.InspectMe.outer()
before test.InspectMe.outer()
after  test.InspectMe.outer()
2但此代码的输出不同

package test

class InspectMe {
    int outer(){
        return inner()
    }
    int inner(){
        return 1
    }
}

def tracer = new TracingInterceptor(writer: new StringWriter())
def proxyMetaClass = ProxyMetaClass.getInstance(InspectMe)
proxyMetaClass.interceptor = tracer
InspectMe inspectMe = new InspectMe()

proxyMetaClass.use(inspectMe){
    inspectMe.outer()
}
println(tracer.writer.toString())
输出:

before test.InspectMe.outer()
  before test.InspectMe.inner()
  after  test.InspectMe.inner()
after  test.InspectMe.outer()
before test.InspectMe.outer()
after  test.InspectMe.outer()
在第二段代码中,TracingInterceptor似乎没有拦截内部方法。 也许这是正常的行为,但在我看来,这就像一只虫子。
有人能解释一下吗

我不知道这是否是一个bug,但我可以解释为什么会发生这种不同的行为。让我们从分析
InspectMe.outer()
方法实现在字节码级别的外观开始(我们反编译.class文件):

//
//IntelliJ IDEA从.class文件重新创建的源代码
//(由Fernflower反编译器提供动力)
//
导入groovy.lang.GroovyObject;
导入groovy.lang.MetaClass;
导入org.codehaus.groovy.runtime.BytecodeInterface8;
导入org.codehaus.groovy.runtime.callsite.callsite;
导入org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
公共类InspectMe实现GroovyObject{
公共视察员(){
CallSite[]var1=$getCallSiteArray();
元类var2=this.$getStaticMetaClass();
this.metaClass=var2;
}
公共int外部(){
CallSite[]var1=$getCallSiteArray();
return!_$stMC&!BytecodeInterface8.disabledStandardMetaClass()?this.internal():DefaultTypeTransformation.intUnbox(var1[0].callCurrent(this));
}
公共int内部(){
CallSite[]var1=$getCallSiteArray();
返回1;
}
}
如您所见,
outer()
方法测试以下谓词

!__$stMC && !BytecodeInterface8.disabledStandardMetaClass()
如果计算结果为
true
,则直接调用
this.inner()
方法,避免使用Groovy的MOP(元对象协议)层(本例中不涉及元类)。否则,它将调用
var1[0].callCurrent(this)
,这意味着
internal()
方法通过Groovy的MOP调用,元类和拦截器参与了它的执行

问题中显示的两个示例提供了设置元类字段的不同方法。在第一种情况下:

def tracer=new tracinterceptor(writer:new StringWriter())
def proxyMetaClass=proxyMetaClass.getInstance(检查我)
proxyMetaClass.interceptor=跟踪程序
InspectMe InspectMe=新InspectMe()

inspectMe.metaClass=proxyMetaClass//回答得很好!它解释了一切。也许这本书的作者至少应该提到这一差异。
/**
 * Use the ProxyMetaClass for the given Closure.
 * Cares for balanced setting/unsetting ProxyMetaClass.
 *
 * @param closure piece of code to be executed with ProxyMetaClass
 */
public Object use(GroovyObject object, Closure closure) {
    // grab existing meta (usually adaptee but we may have nested use calls)
    MetaClass origMetaClass = object.getMetaClass();
    object.setMetaClass(this);
    try {
        return closure.call();
    } finally {
        object.setMetaClass(origMetaClass);
    }
}
BytecodeInterface8.disabledStandardMetaClass()
!__$stMC && !BytecodeInterface8.disabledStandardMetaClass()