Intercept service method calls using metaprogramming in groovy/grails [duplicate]
I have a several Grails services that are invoked from Flex code using Spring BlazeDS integration. I wanted to add some general debug logging using the groovy metaClass. I have the following in a bootstrap class:
class MyBootStrap {
def grailsApplication
def init = { servletContext ->
initServiceCallLogging()
}
def destroy = {
}
private def initServiceCallLogging() {
grailsApplication.serviceClasses.each { serviceClass ->
serviceClass.metaClass.invokeMethod = { name, args ->
log.debug "Method $name invoked"
def metaMethod = delegate.metaClass.getMetaMethod(name, args)
def result = metaMethod.invoke(delegate, args)
return result
}
}
}
}
This works fine as long as t开发者_如何学编程he Service method is called from e.g. a Grails Controller or Service but when directly called from Flex (via BlazeDS), the method calls are not intercepted.
Anyone an idea how this can be solved or is this not possible via metaprogramming and should Spring AOP be used?
Thx
I have no idea why the interception you're attempting is only being called in some cases, the code looks fine to me. It might be worth trying one or both of the following
Suggestion 1
Move the meta-programming out of Bootstrap and into a plugin. I've heard it said that meta-programming like this should always be done in the doWithDynaicMethods
closure of a plugin, rather than Bootstrap, because the Bootstrap is not (always) executed when the application is reloaded at runtime.
Suggestion 2
Instead of intercepting the methods by implementing invokeMethod
on each service's metaClass, you can instead implement invokeMethod on each class directly and make the service implement GroovyInterceptable
. For example, replace:
class MyService {
// implementation
}
With:
class MyService implements GroovyInterceptable {
def invokeMethod(String name, args) {
log.debug "Method $name invoked"
def originalMethod = Car.metaClass.getMetaMethod(name, args)
originalMethod.invoke(this, args)
}
}
An obvious problem with this is that it will require you to add the above boilerplate too all your services. But if it works, maybe you can use it as a starting point towards a DRYer solution.
This works for me. Maybe because of the new version of the BlazeDS plugin.
One suggestion: Instead of writing
log.debug` "Method $name invoked
I use:
delegate.log.debug "Service call: ${name}(${args})"
The advantage is that the logger writes the class where the logging happens instead of bootstrap.
精彩评论