在Groovy中可以很轻松地实现AOP。这里有两种方法可以实现AOP:
- 使用GroovyInterceptable拦截方法
- 使用MetaClass拦截方法
使用GroovyInterceptable拦截方法
如果一个Groovy对象实现了GroovyInterceptable接口,那么当调用该对象上的任何一个方法时——不管是否存在该方法,被调用的都会是invokeMethod()。也就是,GroovyInterceptable上的invokeMethod方法总是会被调用的。
class Car implements GroovyInterceptable{
def check(){
System.out.println("check called...")
}
def start(){
System.out.println("start called...")
}
def drive(){
System.out.println("drive called...")
}
def invokeMethod(String name, Object args) {
System.out.print("call to $name intercepted... ")
if(name != 'check'){
System.out.print("running filter...")
Car.metaClass.getMetaMethod('check').invoke(this,args)
}
def validMethod = Car.metaClass.getMetaMethod(name,args)
if(validMethod != null){
validMethod.invoke(this,args)
}else{
Car.metaClass.invokeMethod(this,name,args)
}
}
}
car = new Car()
car.start()
car.drive()
car.check()
try{
car.stop()
}catch (Exception e){
println e
}
使用MetaClass拦截方法
如果我们用的是第三方的源码或者用的是Java类,那么我们就不能用实现GroovyInterceptable接口的方法进行拦截了。在这种情况下,我们可以在MetaClass上实现invokeMethod()方法,并以此来拦截。
class Auto {
def check() {
System.out.println("check called...")
}
def start() {
System.out.println("start called...")
}
def drive() {
System.out.println("drive called...")
}
}
Auto.metaClass.invokeMethod = { String name, Object args ->
System.out.print("Call to $name intercepted...")
if (name != 'check') {
System.out.print("running filter...")
Auto.metaClass.getMetaMethod('check').invoke(delegate, null)
}
def validMethod = Auto.metaClass.getMetaMethod(name, args)
if (validMethod != null) {
validMethod.invoke(delegate, args)
} else {
Auto.metaClass.invokeMissingMethod(delegate, name, args)
}
}
auto = new Auto()
auto.start()
auto.drive()
auto.check()
try {
auto.stop()
} catch (Exception e) {
println e
}
上面的代码中,以闭包的形式实现了invokeMethod()。同时使用了delegate,delegate指向的是要拦截其方法的目标对象。
如果我们要对POJO进行拦截的话,原理是一样的,看一段对Integer进行拦截的代码。
Integer.metaClass.invokeMethod = {String name,Object args ->
System.out.println("Call to $name interccepted on $delegate...")
def validMethod = Integer.metaClass.getMetaMethod(name,args)
if(validMethod == null){
Integer.metaClass.invokeMissingMethod(delegate,name,args)
}else{
System.out.println("running pre-filter... ")
result = validMethod.invoke(delegate,args)
System.out.println("running post-filter... ")
result
}
}
println 5.floatValue()
println 5.intValue()
try{
println 5.isEmpty()
}catch (Exception e){
println e
}
ps:ExpandoMethodClass是MetaClass接口的一个实现,也是Groovy种负责实现多态行为的关键类之一。通过向该类添加方法可以实现向类中注入行为,甚至可以使用该类特化单个对象。默认情况下,Groovy目前并没有使用ExpandoMethodClass。当我们想metaClass中添加一个方法时,默认的metaClass会被用一个ExpandoMetaClass实例替换掉。(注意obj1,obj2的结果…)
import groovy.transform.Immutable
def printMetaClassInfo(instance){
print "MetaClass of ${instance} is ${instance.metaClass.class.simpleName}"
println " with delegate ${instance.metaClass.delegate.class.simpleName}"
}
printMetaClassInfo(2)
println "MetaClass of Integer is ${Integer.metaClass.class.simpleName}"
println "Adding a method to Integer metaClass"
Integer.metaClass.someNewMethod = {-> /* */}
printMetaClassInfo(2)
println "MetaClass of Integer is ${Integer.metaClass.class.simpleName}"
@Immutable
class MyClass{
String name
}
obj1 = new MyClass("obj1")
printMetaClassInfo(obj1)
println "Adding a method to MyClass metaClass"
MyClass.metaClass.someNewMethod = {-> /* */}
printMetaClassInfo(obj1)
println "obj2 created later"
obj2 = new MyClass("obj2")
printMetaClassInfo(obj2)