« 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

Following up on my own post: I was able to get AOP before, after, and
around advice working.

I've created an example app with tests and with a service that is
wrapped with around advice. It's hosted here for anyone else having
problems:

http://code.google.com/p/grails-aop-hello-world/source/checkout

I've also detailed my problems and solutions here:

http://refactr.com/blog/2009/05/problems-with-aop-in-grails-1-1/

http://refactr.com/blog/2009/06/success-with-aop-in-grails-11/


Hopefully it will help someone in the future.

Scott

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



On Mon, May 11, 2009 at 8:50 AM, Scott Vlaminck <scott@...> wrote:

> 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