9

在我的 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)
            }
        }
    }
}

所以,给定一份工作,比如

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

    def execute() {
        "execute called"
    }
}

它应该打印:

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

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

执行调用

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

如果确实这个错误是我的问题的原因,是否有另一种方法可以“在方法拦截之前”进行?

4

4 回答 4

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() 
  }
}

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

于 2013-05-30T20:25:53.277 回答
3

您可以在应用程序中注册您的自定义以在触发JobListener之前处理逻辑。execute()你可以使用类似的东西: -

public class MyJobListener implements JobListener {
    public void jobToBeExecuted(JobExecutionContext context) {
        println "Before calling Execute"
    }

    public void jobWasExecuted(JobExecutionContext context,
            JobExecutionException jobException) {}

    public void jobExecutionVetoed(JobExecutionContext context) {}
}

Scheduler在 Bootstrap中将自定义的 Job Listener 注册到 Quartz :-

Scheduler scheduler = ctx.getBean("quartzScheduler") //ctx being application context
scheduler.getListenerManager().addJobListener(myJobListener, allJobs())

资源.groovy:-

beans = {
    myJobListener(MyJobListener)
}
  • 我在这里看到使用这种方法的一个好处是我们不再需要用于方法拦截的第二个插件。
  • 其次,我们可以注册监听器来监听所有作业、特定作业和组中的作业。请参阅为JobListenerTriggerListenerScheduleListener自定义 Quartz JobListener和 API 以获得更多见解。
  • 显然,如果我们确实想使用 Quartz API,AOP 是另一种方法。
于 2013-05-30T20:33:11.237 回答
2

你没有得到这样的工作课程。如果你引用 Quartz 插件,你可以通过调用 jobClasses 来获取它们:

application.jobClasses.each {GrailsJobClass tc -> ... }

https://github.com/nebolsin/grails-quartz/blob/master/QuartzGrailsPlugin.groovy

如果你真的看,你会发现他们几乎正在做你想要实现的事情,而不需要使用 aop 或其他任何东西。

于 2013-05-30T19:46:15.047 回答
1

对于方法拦截,在元类上实现 invokeMethod。就我而言,该类不是第三方的,因此我可以修改实现。

关注此博客以获取更多信息。

于 2013-05-30T18:26:26.360 回答