在我的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()之前发生 执行调用
但我对方法拦截的尝试似乎没有效果,而只是打印:
执行调用
问题的原因可能是this Groovy bug?尽管Job类没有显式实现org.quartz.Job
接口,但我怀疑这是隐式的(由于一些Groovy voodoo),它们是这个接口的实例。
如果这个错误确实是我的问题的原因,那么在“方法拦截之前”还有另一种方法吗?
答案 0 :(得分: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提供什么名称都无关紧要。)
答案 1 :(得分: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) {}
}
将定制的Job Listener注册到Bootstrap中的Quartz Scheduler
: -
Scheduler scheduler = ctx.getBean("quartzScheduler") //ctx being application context
scheduler.getListenerManager().addJobListener(myJobListener, allJobs())
resources.groovy: -
beans = {
myJobListener(MyJobListener)
}
答案 2 :(得分:2)
你没有得到那样的工作班。如果您参考Quartz插件,可以通过调用jobClasses来获取它们:
application.jobClasses.each {GrailsJobClass tc -> ... }
请参阅https://github.com/nebolsin/grails-quartz/blob/master/QuartzGrailsPlugin.groovy
如果你真的看,你可以看到他们几乎正在做你想要的事情,而不需要使用aop或其他任何东西。
答案 3 :(得分:1)
对于方法拦截,在元类上实现invokeMethod。在我的情况下,该类不是第三方,所以我可以修改实现。