既然Groovy語言是Java語言的擴展,那麼我們在使用Groovy語言的時候,就很難與Java語言真正脫得了干系,那怕我們是在做一個純Groovy語言的項目,如Grails項目。我們可能在Groovy代碼中會用到遺留的Java類和包;也可能是為了性能的原因,我們不得不在Groovy語言中使用到Java類;等等。
如果我們要對於Java類使用Groovy語言的MOP,比如我們想給一個Java類的對象在運行期內添加一個方法。那麼我們該怎麼辦呢?
比如,我們有如下的一個Java類:
//(Java代碼)
public class Foo {
public String foo()
{
return "foo";
}
}
我們就可以使用如下的方法在運行期內給它的對象添加一個方法:
//(Groovy代碼)
ExpandoMetaClass emc = new ExpandoMetaClass( Foo, false )
emc.hello = {"hello,world!"}
emc.initialize()
上面的代碼用來初始化一個“ExpandoMetaClass”對象,然後添加一個方法,然後將這個對象實例化;這些都跟給Groovy對象在運行期內添加一個方法的過程一樣,沒有什麼好多說的。
接下來,我們的代碼就和對Groovy對象的操作不一樣了,要使用“Proxy”類來包裝我們的Java類對象,如下:
def foo = new groovy.util.Proxy().wrap(new Foo())
然後就是給這個對象賦值上面的“ExpandoMetaClass”對象:
foo.setMetaClass(emc)
最後,我們就可以測試了:
println foo.hello()
運行結果為:
hello,world!
同樣,對於我們上面的Java類,我們也可以使用我們的自定義攔截器來攔截它的動作:
//(Groovy代碼)
class FooInterceptor implements Interceptor{
Object beforeInvoke(Object a_object, String a_methodName, Object[] a_arguments)
{
if(a_methodName == 'foo')
{
println 'before invoking function foo'
}
}
boolean doInvoke()
{
return true
}
Object afterInvoke(Object a_object, String a_methodName, Object[] a_arguments, Object
a_result)
{
a_result
}
}
這個攔截器跟我們攔截Groovy類的自定義攔截器是一模一樣的。使用這個攔截器的方法也是一樣的:
//(Groovy代碼)
def proxy = ProxyMetaClass.getInstance(Foo.class);
proxy.interceptor = new FooInterceptor()
proxy.use {
def foo = new Foo()
println foo.foo()
}
運行結果為:
before invoking function foo
foo
最後一個方法是我們可以通過在“MetaClassRegistry”類上注冊一個“MetaClass”對象來使用Java類擁有“MetaClass”屬性,從而獲得MOP能力。
首先,我們需要自定義一個“MetaClass”類,如下:
//(Groovy代碼)
class FooDelegatingMetaClass extends groovy.lang.DelegatingMetaClass{
FooDelegatingMetaClass(final Class aclass)
{
super(aclass);
initialize()
}
public Object invokeMethod(Object a_object, String a_methodName, Object[] a_arguments)
{
def result
if(a_methodName == 'test')
{
result = 'test'
}
else
{
result = "${super.invokeMethod(a_object, a_methodName, a_arguments)}"
}
result
}
}
這也和其他的自定義“MetaClass”類一樣,不同的是我們在對Java類使用的時候,需要在“MetaClassRegistry”類上注冊。如下:
//(Groovy代碼)
def myMetaClass = new FooDelegatingMetaClass(Foo.class)
def invoker = InvokerHelper.instance
invoker.metaRegistry.setMetaClass(Foo.class, myMetaClass)
注冊完了,我們就可以使用了:
def foo = new Foo()
println foo.test()
一切都很簡單,需要注意的是,在注冊的時候,需要引入如下的類:
import org.codehaus.groovy.runtime.InvokerHelper
最後,我們運行上面的測試代碼,得到如下的結果:
test