Groovy方法拦截

Aba*_*rdi 8 grails groovy metaprogramming

在我的Grails应用程序中,我安装了Quartz插件.我想拦截对每个Quartz作业类方法的调用execute,以便在execute调用方法之前做一些事情(类似于建议之前的AOP).

目前,我正试图通过doWithDynamicMethods关闭另一个插件来执行此拦截,如下所示:

def doWithDynamicMethods = { ctx ->
    // get all the job classes
    application.getArtefacts("Job").each { klass ->

        MetaClass jobMetaClass = klass.clazz.metaClass

        // intercept the methods of the job classes
        jobMetaClass.invokeMethod = { String name, Object args ->

            // do something before invoking the called method
            if (name == "execute") {
                println "this should happen before execute()"
            }

            // now call the method that was originally invoked
            def validMethod = jobMetaClass.getMetaMethod(name, args)

            if (validMethod != null) {
                validMethod.invoke(delegate, args)
            } else {
                jobMetaClass.invokeMissingMethod(delegate, name, args)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

所以,考虑到如此的工作

class TestJob {
    static triggers = {
      simple repeatInterval: 5000l // execute job once in 5 seconds
    }

    def execute() {
        "execute called"
    }
}
Run Code Online (Sandbox Code Playgroud)

它应该打印:

这应该在execute()
执行调用之前发生

但我对方法拦截的尝试似乎没有任何效果,而只是打印:

执行调用

也许问题的原因是这个Groovy错误?即使Job类没有显式实现org.quartz.Job接口,我怀疑是隐式的(由于一些Groovy voodoo),它们是这个接口的实例.

如果这个错误确实是我的问题的原因,那么在"方法拦截之前"还有另一种方法吗?

Dón*_*nal 4

因为所有作业类都是 Spring bean,所以您可以使用 Spring AOP 解决这个问题。定义如下所示的方面(调整切入点定义,使其仅与您的作业类匹配,我假设它们都位于名为 的包中,org.example.job并且具有以 结尾的类名Job)。

@Aspect
class JobExecutionAspect {

  @Pointcut("execution(public * org.example.job.*Job.execute(..))")
  public void executeMethods() {}

  @Around("executeMethods()")
  def interceptJobExecuteMethod(ProceedingJoinPoint jp) {
    // do your stuff that should happen before execute() here, if you need access
    // to the job object call jp.getTarget()

    // now call the job's execute() method
    jp.proceed() 
  }
}
Run Code Online (Sandbox Code Playgroud)

您需要将此方面注册为 Spring bean(给该 bean 起什么名称并不重要)。