Reflection Groovy:在调用任何方法之前和之后透明地执行代码

Reflection Groovy:在调用任何方法之前和之后透明地执行代码,reflection,groovy,closures,metaclass,Reflection,Groovy,Closures,Metaclass,假设我们有一个groovy类,其中包含一些方法(静态或非静态)。 我想做的是在调用该类的每个方法之前和之后执行一些代码,而不涉及该类,也不动态地操作每个方法内部的代码 我尝试使用groovy元类的内容;获取元类的所有方法,然后用包装方法动态替换每种方法,其中包含一些代码,中间调用旧方法。问题是,我不知道每个原始方法的参数,所以我不能用新方法(闭包)替换旧方法,因为我无法动态创建具有不同数量和类型参数的包装闭包,即使yi可以,我也不知道如何在包装闭包内访问它们。我需要包装闭包具有与旧方法相同的签名

假设我们有一个groovy类,其中包含一些方法(静态或非静态)。 我想做的是在调用该类的每个方法之前和之后执行一些代码,而不涉及该类,也不动态地操作每个方法内部的代码

我尝试使用groovy元类的内容;获取元类的所有方法,然后用包装方法动态替换每种方法,其中包含一些代码,中间调用旧方法。问题是,我不知道每个原始方法的参数,所以我不能用新方法(闭包)替换旧方法,因为我无法动态创建具有不同数量和类型参数的包装闭包,即使yi可以,我也不知道如何在包装闭包内访问它们。我需要包装闭包具有与旧方法相同的签名,以便在类被透明地更改后,当有人试图调用旧方法时调用闭包

例如,在Javascript中,我可以使用args[]数组访问函数体中的所有参数,即使我在编写代码时不知道参数名称


如何在groovy中实现这一点?或者他们可能是实现我所尝试的目标的另一种方式吗?

下面这样的方法可以吗?使用
invokeMethod
拦截对每个方法的调用。测试是不言自明的

说明:

class Dummy {
    def method1() { System.out.println "In method 1" }
    def method2(String str) { System.out.println "In method 2" }
    static def method3(int a, int b) { 
        System.out.println "In static method 3" 
    }    
}

Dummy.metaClass.invokeMethod = {String name, args ->
   def result

   System.out.println(
     "Do something before $name is called with args $args")

   try {
      result = delegate.metaClass.getMetaMethod(name, args)
                                 .invoke(delegate, args)
   } catch(Exception e) {
       System.out.println "Handling exception for method $name"
   }

   System.out.println(
      "Do something after $name was called with args $args \n")

   result
}

Dummy.metaClass.'static'.invokeMethod = {String name, args ->
   def result

   System.out.println(
     "Do something before static method $name is called with args $args")

   try {
      result = delegate.metaClass.getMetaMethod(name, args)
                                 .invoke(delegate, args)
   } catch(Exception e) {
       System.out.println "Handling exception for method $name"
   }

   System.out.println(
     "Do something after static method $name was called with args $args \n")

   result
}

def dummy = new Dummy()
dummy.method1()
dummy.method2('Test')
Dummy.method3(1, 2)
下面是元类实现重写的invokeMethod。由于所有groovy对象都继承自GroovyObject,因此我们可以灵活地操作/拦截方法调用,甚至可以指定自己的
methodMissing
实现。我们需要一个用于静态方法的重写,另一个用于非静态方法。基本上,invokeMethod截获对定义它的类上的每个方法的调用。最后,我们为每个方法提供了一些
功能。使用反射,下面的实现能够通过名称和参数找到方法,并在运行时调用它

注意:-

  • 确保方法调用返回的值也从闭包返回
  • 一个类有很多方法,实现量很大,这可能会很昂贵
  • 如果需要选择性执行,则检查方法名称,然后拦截调用
实施:

class Dummy {
    def method1() { System.out.println "In method 1" }
    def method2(String str) { System.out.println "In method 2" }
    static def method3(int a, int b) { 
        System.out.println "In static method 3" 
    }    
}

Dummy.metaClass.invokeMethod = {String name, args ->
   def result

   System.out.println(
     "Do something before $name is called with args $args")

   try {
      result = delegate.metaClass.getMetaMethod(name, args)
                                 .invoke(delegate, args)
   } catch(Exception e) {
       System.out.println "Handling exception for method $name"
   }

   System.out.println(
      "Do something after $name was called with args $args \n")

   result
}

Dummy.metaClass.'static'.invokeMethod = {String name, args ->
   def result

   System.out.println(
     "Do something before static method $name is called with args $args")

   try {
      result = delegate.metaClass.getMetaMethod(name, args)
                                 .invoke(delegate, args)
   } catch(Exception e) {
       System.out.println "Handling exception for method $name"
   }

   System.out.println(
     "Do something after static method $name was called with args $args \n")

   result
}

def dummy = new Dummy()
dummy.method1()
dummy.method2('Test')
Dummy.method3(1, 2)