4

I am having trouble getting multiple aspects to fire in a specific order. I am using the RequestProcessor to do certain things on every incoming request on my controllers, which have a certain parameter

Then I have some specific annotations that I will be adding to only certain methods within my controllers.

FYI I am using Eclipse, Tomcat, Maven and spring with java/annotation based configs. I use Tomcat and the WebApplicationInitializer to load my context, dispatcher, listeners etc. I have no web.xml. I can post that or the pom.xml if needed too.

The problem I am getting is that a method that satisfies both the ProcessRequest pointcut and the someAnnotation pointcut is firing the someAnnotation method first even though the order is specified to fire ProcessRequest first. There is some properties set in the ProcessRequest that is needed in some other annotations.

Here is a simplified version of my code.

Spring Config Class

@Configuration  // Enable Spring Annotation Configuration. Equivalent to <context:annotation-config/>
@EnableAspectJAutoProxy
@EnableCaching  // Enable Spring caching
@EnableWebMvc   // Enable Spring MVC Annotation. Equivalent to <mvc:annotation-driven />.
@ComponentScan(basePackages = {"xxx.yyy.zzz"}) // Scan for Spring Components.      Equivalent to <context:component-scan>
public class WebAppConfig extends WebMvcConfigurerAdapter {

    // Other Bean logic here

    @Bean
    public RequestProcessor requestProcessor() {
        return new RequestProcessor();
    }

    @Bean
    public AnnotationAspect annotationAspect() {
        return new AnnotationAspect();
    }
}

Aspect #1

@Aspect
@Order(0)
public class RequestProcessor {

    @Pointcut("execution(* xxx.yyy.zzz.api..*.*(xxx.yyy.zzz.objects.api.Request,..)) && args(request)")
    public void pointcut(Request<?> request) {}

    @Before("pointcut(request)")
    public void processRequest(Request<?> request) throws IOException, BadSignatureException {
        // Some logic here that is independent of other and needs to run before other aspect which references annotation
    }
}

Aspect #2

@Aspect
@Order(1)
public class AnnotationAspect {

    @Before("@annotation(xxx.yyy.zzz.annotation.SomeAnnotation)")
    public void someAnnotation() {
        // Log for this annotation
    }

    // Some other annotation methods here
}

Also tried this format implements Ordered

@Aspect
public class RequestProcessor implements Ordered {

    @Override
    public int getOrder() {
        return 0;
    }

    @Pointcut("execution(* xxx.yyy.zzz.api..*.*(xxx.yyy.zzz.objects.api.Request,..)) && args(request)")
    public void pointcut(Request<?> request) {}

    @Before("pointcut(request)")
    public void processRequest(Request<?> request) throws IOException, BadSignatureException {
        // Some logic here that is independent of other and needs to run before other aspect which references annotation
    }
}

I read over this post and some others but couldn't find anything relevant that worked.

Ordering aspects with Spring AOP && MVC

****UPDATE****

So I have been reading through the AspectJ docs on declaring precedence so I thought I would give it a whirl. I created a simple aspect that only declares precedence and it works just fine.

Here is my Precedence Aspect:

public aspect AspectPrecedence {
    declare precedence : RequestProcessor, SomeAspect;
}

I am not going to submit this as answer just yet because I would like to understand why the annotation or "implements Ordered" are not functioning properly in my project.

Any insight would be greatly appreciated. Thanks!

****UPDATE 2****

For reference this works locally in my eclipse environment and seemed to work when deployed to AWS via WAR file.

@Aspect
@DeclarePrecedence("RequestProcessor, SomeAspect")
public class RequestProcessor {

    @Pointcut("execution(* xxx.yyy.zzz.api..*.*(xxx.yyy.zzz.objects.api.Request,..)) && args(request)")
    public void pointcut(Request<?> request) {}

    @Before("pointcut(request)")
    public void processRequest(Request<?> request) throws IOException, BadSignatureException {
        // Some logic here that is independent of other and needs to run before other aspect which references annotation
    }
}
Community
  • 1
  • 1
PJH
  • 497
  • 4
  • 12
  • In the example you show, the order begins at 1. Maybe it's nohing but it worth a try ^^ – Julien Oct 31 '13 at 16:37
  • 1
    Thanks I did try 1 and 2 instead still nothing. Even if I use 1 and 50 it still isn't working correctly. – PJH Oct 31 '13 at 17:12
  • Always working incorrectly –  Oct 31 '13 at 17:24
  • 1
    WHEN isn't it working? After building a war with maven (from the command-line) and deploying it to tomcat. Or running the project from within eclipse? In general the latter uses compile-time weaving, which doesn't do anything with `@Order` or `Ordered`. – M. Deinum Oct 31 '13 at 19:22
  • Thanks for the comment that makes sense. I didn't realize that they would be different. Personally I was just testing this on my local pc via eclipse and didn't bother to try deploying it to test. That would be frustrating not being able to test your implementation before deploying it out. – PJH Oct 31 '13 at 21:29
  • @M.Deinum You may want to submit that as the solution because I have verification now. Using `@DeclarePrecedence` works locally but deployed out with the war file I get a stack trace saying `@DeclarePrecedence is not supported by Spring AOP` The only thing that is working for both local and deployed for me is having a simple aspect that declares the precedence. – PJH Nov 01 '13 at 18:33
  • @PJH I am aslo getting "@DeclarePrecedence is not supported by Spring AOP" Is there any workaround other than creating a simple aspect that declares the precedence. – Vaibhav Gupta Oct 31 '15 at 13:42

2 Answers2

4

When using Eclipse with AspectJ support that automatically enables compile time weaving in your IDE. Which means the aspects get woven into your byte code, opposed to Spring which uses proxies to apply aspects.

Using an aspect to declare precedence or using @DeclarePrecedence will only work when using either compile or load time weaving (the latter can be enabled by specifying <context:load-time-weaver/> depending on your container might require some additional configuration). However both should work (you might need to specify the AspectJ compiler as a compiler for the @Aspect classes instead of the default java compiler).

@Order and Ordered only work for the proxy based solution and are ignored by AspectJ.

M. Deinum
  • 115,695
  • 22
  • 220
  • 224
1

I think the problem could be that you're using LTW with AspectJ instead AOP with Spring, as @Order is defined for Spring, the container(AspectJ) is not able to determine the ordering of both the advices, so try one of these:

  1. Try flipping the order of @Aspect and @Order annotations
  2. You can try the annotation @DeclarePrecedence from AspectJ and then configuring your aspects into the aop.xml
<aspects>        
        <aspect name="your.package.RequestProcessor"/>
        <aspect name="your.package.AnnotationAspect"/>
           <concrete-aspect name="my_aspect_configuration_precedence"
                precedence="*..*RequestProcessor, *"/>
</aspects>

I don't know if it's going to work but expect to give you a pointer on that

Diego Jimeno
  • 312
  • 4
  • 15
  • Yeah tried the 1st one you suggested. Can't remember where I saw it and that one didn't work. The second one I had not tried yet so went ahead and tried this `@DeclarePrecedence("RequestProcessor, SomeAspect")` and that didn't work either. Wonder why its not picking up the `@Order` or `@DeclarePrecedence` annotations but it is picking up the `@Aspect` one. – PJH Oct 31 '13 at 20:29
  • Scratch that... just noticed I had a typo in my `@DeclarePrecedence` statement and tried it again. Now it works and I can remove the simple aspect class to declare precedence. Thanks! Also as an aside... I did not need to declare any aop.xml since I have the annotations present and it still works. – PJH Oct 31 '13 at 20:32
  • FYI... the per M.Deinum's comment above and I verified testing this... the `@DeclarePrecedence` works with the eclipse compiler for local testing but when deployed out via war file to tomcat I get a stacktrace saying `@DeclarePrecedence is not supported by Spring AOP`. This means that the `@Order` annotation should work deployed but isn't working locally via eclipse. The only thing that works for both is creating a simple aspect with the declare precedence. – PJH Nov 01 '13 at 18:42