Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to ensure annotations execution order in java?

i have 2 custom annotations, but one should always executed before the other. How do i ensure this? Is there some kind of ordering or do it with additional method definitions?

like image 383
user358448 Avatar asked Jan 14 '13 12:01

user358448


4 Answers

From http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/aop.html#aop-ataspectj-advice-ordering

Spring AOP follows the same precedence rules as AspectJ to determine the order of advice execution. The highest precedence advice runs first "on the way in" (so given two pieces of before advice, the one with highest precedence runs first). "On the way out" from a join point, the highest precedence advice runs last (so given two pieces of after advice, the one with the highest precedence will run second).

When two pieces of advice defined in different aspects both need to run at the same join point, unless you specify otherwise the order of execution is undefined. You can control the order of execution by specifying precedence. This is done in the normal Spring way by either implementing the org.springframework.core.Ordered interface in the aspect class or annotating it with the Order annotation. Given two aspects, the aspect returning the lower value from Ordered.getValue() (or the annotation value) has the higher precedence.

When two pieces of advice defined in the same aspect both need to run at the same join point, the ordering is undefined (since there is no way to retrieve the declaration order via reflection for javac-compiled classes). Consider collapsing such advice methods into one advice method per join point in each aspect class, or refactor the pieces of advice into separate aspect classes - which can be ordered at the aspect level.

like image 137
Emerson Farrugia Avatar answered Nov 09 '22 17:11

Emerson Farrugia


You can ensure the order of your custom annotations with @Order annotation.

https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/Order.html

Example:

First annotation:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CustomAnnotation {
}

@Aspect
@Component
@Order(value = 1)
public class CustomAnnotationInterceptor {

    @Before("@annotation(customAnnotation )")
    public void intercept(JoinPoint method, CustomAnnotation customAnnotation ) {
        //Code here
    }
}

Second annotation:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CustomAnnotationTwo {
}

@Aspect
@Component
@Order(value = 2)
public class CustomAnnotationInterceptorTwo {

    @Before("@annotation(customAnnotationTwo )")
    public void intercept(JoinPoint method, CustomAnnotationTwo customAnnotationTwo ) {
        //Code here
    }

Using them:

@CustomAnnotationTwo
@CustomAnnotation
public void someMethod(){
}

In this example, CustomAnnotationInterceptor will execute first.

like image 29
Roman Avatar answered Nov 09 '22 18:11

Roman


Checkout https://stackoverflow.com/a/30222541/810109: At least in Java 8 you can retrieve annotations in a guaranteed order, so you just have to declare them in the right order.

like image 25
mkurz Avatar answered Nov 09 '22 17:11

mkurz


I know this is very old question, but I just wanted to document my findings. Can anyone please confirm if these are correct? It is already mentioned in this page that Spring documentation says that execution of annotations is undefined unless @Order annotation is used. I tried to rename the Aspect classes, and tested many times, and found that Aspect classes are executed in alphabetical order of their names and found that the result is consistent.

Below is my sample code:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface A {}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface B {}

@Aspect
public class A_Aspect {

@Around("@annotation(mypackage.A)")
public void around(ProceedingJoinPoint joinPoint) {
    System.out.println("A_Aspect");
    joinPoint.proceed();
    }
}

@Aspect
public class B_Aspect {

    @Around("@annotation(mypackage.B)")
    public void around(ProceedingJoinPoint joinPoint) {
        System.out.println("B_Aspect");
        joinPoint.proceed();
    }
}

class AdvisedClass{
    @B
    @A
    public void advisedMethod(){}
}

When I tried to execute advisedMethod(), following are the logs I received:

A_Aspect
B_Aspect

I changed annotation declaration sequence:

@A
@B  
public void advisedMethod(){}

Following are the logs:

A_Aspect
B_Aspect

I renamed Annotation @A to @C, Following are the logs:

A_Aspect
B_Aspect

But, when I tried to rename Aspect class A_Aspect to C_Aspect, Following are the logs:

B_Aspect
C_Aspect

As I said, I want someone to confirm this as I could not find any documentation for this

like image 22
Atul Kumbhar Avatar answered Nov 09 '22 18:11

Atul Kumbhar