今天要跟大家分享Groovy裡面interceptor如何使用,有兩種方式可以做到before method做什麼事情或是after method做什麼事情,一則是先宣告一個class實作GroovyInterceptable,override invokeMethod,另一種是宣告TracingInterceptor,在指定給ProxyMetaClass中interceptor屬性,兩者都可以達到相同目的,只是後者Groovy幫我們減少了很多coding,若有學過Spring的AOP的話,應該會發現少了很多程式碼,不用指定pointcut, aspect等一堆....
第一種方法首先必須import org.codehaus.groovy.runtime.InvokerHelper,協助我們在runtime取得對應之metaclass,以方便操作,再來如上述宣告class實作GroovyInterceptable
,接著宣告一個dummy的class,裡面包幾個簡單的方法呼叫彼此,以測試before/after method駛後有被觸發
package intro
import org.codehaus.groovy.runtime.InvokerHelper //一定要宣告
import org.codehaus.groovy.runtime.StringBufferWriter //用來runtime時寫入log
class gInterceptor implements GroovyInterceptable {
Writer writer=new PrintWriter(System.out)
//override invokeMethod
Object invokeMethod(String name, Object args){
writer.write("Before Calling Method ${name}")
writer.write("\n")
writer.flush()
def metaClass = InvokerHelper.getMetaClass(this)
//InvokerHelp方法就是在runtime到MetaRegistry找出此class對應的metaclass
def result = metaClass.invokeMethod(this, name, args)
//記錄每一次呼叫方法
writer.write("After Calling Method ${name}")
writer.write("\n")
writer.flush()
return result //第一次回傳second(),第二回傳third(),直到不是方法為止
//並繼續執行invokeMetho內的程式碼
}
}
class subMethod extends gInterceptor {
String first(){
return second()
}
String second(){
return third()
}
String third(){
return 'Hello! This is the last method call'
}
}
def log=new StringBuffer()
def testInterceptor=new gInterceptor(writer: new StringBufferWriter(log))
def callingMethod =new subMethod()
print callingMethod.first()
執行結果:
Before Calling Method first
Before Calling Method second
Before Calling Method third
After Calling Method third
After Calling Method second
After Calling Method first
Hello! This is the last method call
第二種方法則需要透過Groovy特別為interceptor功能設計ProxyMetaClass,另搭配TracingInterceptor,TracingInterceptor應該可以override其中的方法,但簡單範例就已預設的實作demo,程式碼如下。
import org.codehaus.groovy.runtime.StringBufferWriter
//無須再import InvokerHelper
class proxyMethod{ //dummy的class
String first(){
return second()
}
String second(){
return third()
}
String third(){
return 'Hello! This is the last method call'
}
}
def log=new StringBuffer("\n")
def gInterceptor= new TracingInterceptor()
//new一個TracingInterceptor物件,沒有其他coding的話就是預設實作
def proxy=ProxyMetaClass.getInstance(proxyMethod.class)
//取得ProxyMetaClass物件並指定要攔截的class
proxy.interceptor =gInterceptor
//將TracingInterceptor物件實作指定給ProxyMetaClass
proxy.use{
//Use語法(Category),表示呼叫proxyMethod時以proxy class處理
new proxyMethod().first()
}
println log.toString();
print new proxyMethod().first()
執行結果如下:
before proxyMethod.ctor()
after proxyMethod.ctor()
before proxyMethod.first()
before proxyMethod.second()
before proxyMethod.third()
after proxyMethod.third()
after proxyMethod.second()
after proxyMethod.first()
Hello! This is the last method call
兩個結果不同的是TracingInterceptor還會觸發ctor()這個方法,另外其預設實作是有縮排的,比較美觀,當然interceptor不可能僅僅只能印出訊息,更多應用應該在Grails裡會提到。