« Return to Thread: Grails and Spring AOP

Re: Re: Grails and Spring AOP

by Scott Vlaminck :: Rate this Message:

Reply to Author | View in Thread

I'm also having problems with AOP in Grails 1.1. I can't seem to get
around advice working on a Grails Service. I get no error, but my
aspect is not invoked.

To simplify everything, I created a simple Hello World app that does
almost nothing: my controller calls my service and both print log
messages. The service implements an interface as described earlier in
this thread (the interface is defined in src/groovy) and my aspect
just logs before and after the method invocation (the aspect is
defined in grails-app/utils).

I've tried a number of different ways of configuring the aspect in
resources.groovy, but nothing seems to change (except I do get errors
on startup if I define the aspect incorrectly in resources.groovy).
I've even tried defining my Service and interface in the default
package and in their own package.

This is my first time using Spring AOP, so I must be missing something
simple. Any thoughts are very much appreciated. I uploaded my hello
world app to google code for anyone interested:
http://code.google.com/p/grails-aop-hello-world/

Also, the relevant bits of my app are included below in case someone
has any ideas.

Thanks,
Scott


Service:
------------------------------
public class TheService implements TheServiceInterface {
        def service(Integer i) {
                log.debug "TheService.service(${i})"
                println "TheService.service(${i})"
                return "Hello world"
        }
}
------------------------------


Aspect:
------------------------------
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class TheAspect implements MethodInterceptor {
    public Object invoke(MethodInvocation method) throws Throwable
        {
        log.debug("Before Invoking Method");
        println("Before Invoking Method");

        Object val = method.proceed();

        log.debug("After Invoking Method");
        println("After Invoking Method");

        return val + "updated value";
    }

 // not sure if this method is necessary or even doing anything
    public Object invoke(MethodInvocation method, Integer i) throws Throwable {
        log.debug("Before Invoking Method with ${i}");
        println("Before Invoking Method with ${i}");

        Object val = method.proceed();

        log.debug("After Invoking Method with ${i}");
        println("After Invoking Method with ${i}");

        return val + "updated value";
    }
}
------------------------------


I've tried a number of different config changes in resources.groovy
(one at a time). Below are two versions that seem like they should
each work.

conf/spring/resources.groovy:
------------------------------
theAspect(TheAspect)

// config version 1
aop {
        config {
                aspect(ref:"theAspect") {
                        pointcut id:"thePointcut", expression:"execution(*
TheServiceInterface.service(Integer)) && args(i)"
                        around 'pointcut-ref':"thePointcut", method:"invoke", 'arg-names':"i"
                }
        }
}

// config version 2
aop {
        config("proxy-target-class":true) {
                aspect(id:"theAspectId", ref:"theAspect" ) {
                        around method:"invoke", pointcut: "execution(*
TheServiceInterface.service(Integer)) && args(i)", 'arg-names':"i"
                }
        }
}
------------------------------




Again, any thoughts or pointers are appreciated. Thanks in advance.



-------------------------------------------------
Scott Vlaminck // scott@...
Refactr LLC // http://refactr.com
mobile // 612-386-9382
-------------------------------------------------



On Mon, Oct 20, 2008 at 6:08 AM, Matthias <m.kaeppler@...> wrote:

> Guys,
>
> I have got it working, somehow, but it involves a workaround which I am not
> happy with. First, two things seem to be required in order for advice being
> applied to an object in Grails:
>
> 1) As has been said before, it must be of the same type that is referenced in
> the aspect declaration, otherwise an "instance is not of declaring type" error
> is thrown. This can be solved by implementing an interface and match the
> pointcut against that interface.
>
> 2) The object that is being advised must be a Spring bean, i.e. it must be
> managed by the container. This is not true for Grails Controllers, and this
> is the reason why I was able to apply advice to my services, but not to my
> controllers.
>
> Unfortunately, controllers are instantiated per-request and parameters
> bound as such. So what I did was for each controller create an interface
> and an implementation of that interface, to which the controller closures
> forward, e.g.:
>
> interface Foo {
>   def foo(def controller)
> }
>
> // this must be a managed bean
> class FooImpl {
>   def foo(def controller) {
>       controller.flash.message = "advice applied!"
>   }
> }
>
> class FooController {
>   def impl // injected by spring
>
>   def fooClosure = {
>       // forward call
>       impl.foo(this)
>   }
> }
>
> Now any advice declared on Foo will match, however, this solution has many
> drawbacks: Firstly, of course, another level of indirection is introduced,
> with all the related drawbacks (performance, readability, ...)
> Secondly, all controller logic is now moved to FooImpl, but FooImpl needs
> access to "private" controller fields (e.g. params, flash, ...).
> Given, right now there is no such thing as private fields or methods in
> Groovy, but this may change with upcoming versions I guess and break
> this workaround (unless there will be public getters for everything).
> Lastly, every controller impl has to be declared manually as a bean.
>
> So, does anyone have a better solution at hand, because I am not very
> happy with this.
>
> Thanks and best regards,
> Matthias
>
>
> ---------------------------------------------------------------------
> To unsubscribe from this list, please visit:
>
>    http://xircles.codehaus.org/manage_email
>
>
>

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


 « Return to Thread: Grails and Spring AOP