Reputation: 497
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
}
}
Upvotes: 4
Views: 8131
Reputation: 124581
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.
Upvotes: 4
Reputation: 312
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:
@Aspect
and @Order
annotations@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
Upvotes: 1