Groovy-ProxyMetaClass的拦截器不影响内部方法调用
代码片段来自《Groovy in action 2nd》一书,稍作修改 1此代码按预期工作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
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()