如何使用 Groovy 拦截 Java 应用程序中所有方法的执行?

发布于 2024-07-30 06:30:54 字数 133 浏览 1 评论 0原文

是否可以拦截应用程序中调用的所有方法? 我想和他们一起做一些事情,然后让他们执行。 我尝试在 Object.metaClass.invokeMethod 中重写此行为,但它似乎不起作用。

这可行吗?

Is it possible to intercept all the methods called in a application? I'd like to do something with them, and then let them execute. I tried to override this behaviour in Object.metaClass.invokeMethod, but it doesn't seem to work.

Is this doable?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

情定在深秋 2024-08-06 06:30:54

首先,重写 Object.metaClass.invokeMethod 不起作用,因为当 Groovy 尝试解析类型 X 的方法调用时,它会检查 X 的元类,而不是其父类的元类(es)。 例如,以下代码将打印“method intValue拦截”,

Integer.metaClass.invokeMethod = {def name, def args ->
  System.out.println("method $name intercepted")
}

6.intValue()

// Reset the metaClass  
Integer.metaClass = null  

但此代码不会:

Object.metaClass.invokeMethod = {def name, def args ->
  System.out.println("method $name intercepted")
}

6.intValue()

// Reset the metaClass  
Object.metaClass = null

您的问题是“是否可以拦截应用程序中调用的所有方法?”,但是您能否更准确地说明您是否想要to:

  • 拦截对 Groovy 方法、Java 方法或两者的
  • 调用 仅拦截对您的 Groovy/Java 方法的调用,或者拦截对 Groovy/Java 库类的调用

例如,如果您只想拦截对您的 Groovy 类,您可以更改类以实现 GroovyInterceptable。 这可确保为这些类上调用的每个方法调用 invokeMethod()。 如果拦截的性质(即您想要在调用被调用方法之前/之后执行的操作)对于所有类都相同,则可以在单独的类中定义 invokeMethod() 并使用 @Mixin 将其应用到您的所有类。

或者,如果您还想拦截对 Java 类的调用,您应该查看 委托元类

First of all, overriding Object.metaClass.invokeMethod doesn't work because when Groovy tries to resolve a method call for a type X, it checks the metaClass of X, but not the metaClass of its parent class(es). For example, the following code will print "method intValue intercepted"

Integer.metaClass.invokeMethod = {def name, def args ->
  System.out.println("method $name intercepted")
}

6.intValue()

// Reset the metaClass  
Integer.metaClass = null  

But this code will not:

Object.metaClass.invokeMethod = {def name, def args ->
  System.out.println("method $name intercepted")
}

6.intValue()

// Reset the metaClass  
Object.metaClass = null

Your question was "Is it possible to intercept all the methods called in a application?", but could you be a bit more precise about whether you want to:

  • Intercept calls to Groovy methods, Java methods, or both
  • Intercept calls to only your Groovy/Java methods or also intercept calls to Groovy/Java library classes

For example, if you only want to intercept calls to your Groovy classes, you could change your classes to implement GroovyInterceptable. This ensures that invokeMethod() is invoked for every method called on those classes. If the nature of the interception (i.e. the stuff you want to do before/after invoking the called method) is the same for all classes, you could define invokeMethod() in a separate class and use @Mixin to apply it to all your classes.

Alternatively, if you also want to intercept calls to Java classes, you should check out the DelegatingMetaClass.

所谓喜欢 2024-08-06 06:30:54

你看过 Groovy AOP 吗? 文档很少,但它允许您可以使用与 AspectJ 概念上类似的方式定义切入点和建议。 看看 单元测试更多示例

下面的示例将匹配对所有编织类型的所有调用,并在继续之前应用建议:

// aspect MyAspect
class MyAspect {
  static aspect = {
    //match all calls to all calls to all types in all packages
    def pc = pcall("*.*.*")

    //apply around advice to the matched calls
    around(pc) { ctx ->
      println ctx.args[0]
      println ctx.args.length
      return proceed(ctx.args)
    }
  }
}
// class T
class T {
  def test() {
    println "hello"
  }
}
// Script starts here
weave MyAspect.class
new T().test()
unweave MyAspect.class

Have you looked at Groovy AOP? There's very little documentation, but it allows you to define pointcuts and advice in a conceptually similar way as for AspectJ. Have a look at the unit tests for some more examples

The example below will match all calls to all woven types and apply the advice before proceeding:

// aspect MyAspect
class MyAspect {
  static aspect = {
    //match all calls to all calls to all types in all packages
    def pc = pcall("*.*.*")

    //apply around advice to the matched calls
    around(pc) { ctx ->
      println ctx.args[0]
      println ctx.args.length
      return proceed(ctx.args)
    }
  }
}
// class T
class T {
  def test() {
    println "hello"
  }
}
// Script starts here
weave MyAspect.class
new T().test()
unweave MyAspect.class
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文