Groovy:在调用任何方法之前和之后执行代码透明 [英] Groovy: Execute Code transparent before and after any method is invoked

查看:193
本文介绍了Groovy:在调用任何方法之前和之后执行代码透明的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们假设我们有一个groovy类有一些方法(静态或非静态)。
我想做的是在调用这个类的每个方法之前和之后执行一些代码,而不需要触摸该类,而且不需要动态操作每个方法中的代码。



我试过使用groovy metaClass;获取metaClass的所有方法,然后使用包装方法动态替换每个方法,包含一些代码,并在中间调用旧方法。问题是,我不知道每个原始方法的参数,所以我不能用新的方法(闭包)替换旧的方法,因为我不能创建动态包含不同数量和类型的参数的包装闭包,即使yi可能,i不知道如何在包装封闭件内接近它们。我需要包装闭包有相同的老方法的签名,所以当有人尝试调用旧方法后,透明地更改类后调用闭包。



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



我可以在groovy这样做吗?

解决方案

下面的东西会做什么?使用 invokeMethod 可拦截对每个方法的调用。测试是自解释性的。



说明:



下面的metaClass实现覆盖invokeMethod GroovyObject 。由于所有groovy对象都继承自GroovyObject,因此我们获得了操纵/拦截方法调用的灵活性,甚至指定了我们自己的 methodMissing 实现。我们需要一个覆盖静态和一个非静态方法。基本上,invokeMethod拦截对其定义的类的每个方法的调用。对于每个方法,我们最终会在之前加上之前的。使用反射下面的实现能够通过其名称和参数找到该方法并在运行时调用它。



注意: - p>


  • 确保方法调用的返回值也是从闭包返回的

  • 可能是

如果需要选择性执行,则检查方法名称,然后拦截调用


实施:

  class Dummy {
def method1(){System.out.println在方法1}
def method2(String str){System.out.println在方法2}
static def method3 ,int b){
System.out.println在静态方法3
}
}

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

System.out.println(
使用args $ args调用$ name之前的操作)

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

System.out.println(
使用args $ args \\\
调用$ name后的操作)

result
}

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

System.out.println(
在静态方法前执行某项操作,使用args $ args调用$ name)

try {
result = delegate.metaClass.getMetaMethod(name,args)
.invoke(delegate,args)
} catch(Exception e){
System.out.printlnHandling exception对于方法$ name
}

System.out.println(
在静态方法后执行操作$ name使用args $ args \\\
调用)

result
}

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


Let's say we have a groovy class with some methods (static or not static). What i want to do is executing some code before and after every method of this class is invoked without touchung the class at all and without dynamically manipulating the code inside of each method.

What i tried using groovy metaClass; getting all methods of the metaClass and then dynamically replacing the every method with a wrapping method, containing some code and in the middle invoking the old method. Problem is, i don't know the parameters of each original method so i can't replace the old methods with new methods (closures) because i cannot create wrapping closures with varying numbers and types of parameters dynamically and even if yi could, i didn't know how to access them inside the wrapping closure. I need that the wrapping closure has the same signature of the old method so that the closure gets called when someone tries to call the old method after the class was transparently changed.

In Javascript e.g. i can use the args[] array to access all arguments in a function body even if i don't know the arguments names at the time when writing the code.

How can i do this in groovy? Or is their maybe another way to achieve what i try to do?

解决方案

Something like below will do? Using invokeMethod to intercept calls to each method. Test is self explanatory.

Explanation:

Below metaClass implementation overrides invokeMethod from GroovyObject. Since all groovy objects inherit from GroovyObject, we gain the flexibility of manipulating/intercepting method calls or even specify our own methodMissing implementation. We would need one override for static and one for non-static methods. Basically, invokeMethod intercepts calls to each method on the Class on which it is defined. We end up with some before and after functionalities for each method. Using reflection the below implementation is able to find out the method by its name and argument and invoke it in runtime.

Note:-

  • Make sure the returned value from the method call is returned from the closure as well
  • Might be a expensive of a class has number of methods with heavy implementation
  • If selective execution is required, then check for the method name and then intercept the call

Implementation:

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)

这篇关于Groovy:在调用任何方法之前和之后执行代码透明的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆