java java中如何保证注解的执行顺序?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14318438/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 15:52:02  来源:igfitidea点击:

How to ensure annotations execution order in java?

javaspringannotations

提问by user358448

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?

我有 2 个自定义注释,但一个应始终在另一个之前执行。我如何确保这一点?是否有某种排序或使用其他方法定义进行排序?

回答by Roman

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

您可以使用 @Order 注释来确保自定义注释的顺序。

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

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.

在这个例子中,CustomAnnotationInterceptor 将首先执行。

回答by Atul Kumbhar

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.

我知道这是一个非常古老的问题,但我只是想记录我的发现。任何人都可以确认这些是否正确?在这个页面中已经提到,Spring 文档说除非使用 @Order 注释,否则注释的执行是未定义的。尝试重命名Aspect类,测试了很多次,发现Aspect类都是按照名字的字母顺序执行的,结果是一致的。

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:

当我尝试执行 noticeMethod() 时,以下是我收到的日志:

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 重命名为@C,以下是日志:

A_Aspect
B_Aspect

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

但是,当我尝试将 Aspect 类 A_Aspect 重命名为 C_Aspect 时,以下是日志:

B_Aspect
C_Aspect

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

正如我所说,我希望有人确认这一点,因为我找不到任何相关文件

回答by Emerson Farrugia

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

来自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).

Spring AOP 遵循与 AspectJ 相同的优先级规则来确定通知执行的顺序。最高优先级的建议首先在“进入的路上”运行(因此给定两条 before 建议,优先级最高的一条最先运行)。从连接点“出路”,最高优先级的建议最后运行(因此给定两条后建议,具有最高优先级的将第二运行)。

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.

当在不同方面定义的两条通知都需要在同一个连接点运行时,除非您另行指定,否则执行顺序是未定义的。您可以通过指定优先级来控制执行顺序。这是通过在方面类中实现 org.springframework.core.Ordered 接口或使用 Order 注释对其进行注释以普通 Spring 方式完成的。给定两个方面,从 Ordered.getValue() 返回较低值的方面(或注释值)具有更高的优先级。

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.

当在同一方面定义的两条通知都需要在同一连接点运行时,排序是未定义的(因为无法通过 javac 编译类的反射检索声明顺序)。考虑将这些建议方法合并为每个方面类中的每个连接点的一个建议方法,或者将建议片段重构为单独的方面类 - 可以在方面级别进行排序。

回答by mkurz

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.

结帐https://stackoverflow.com/a/30222541/810109:至少在 Java 8 中,您可以按有保证的顺序检索注释,因此您只需按正确的顺序声明它们。

回答by Amol Fasale

You can do it by using EJB interceptors.

您可以通过使用 EJB 拦截器来实现。

you can simply add interceptors via @Interceptors( { MyInterceptor.class } ) and then add for second one @MyInterceptorConfiguration(value=something).

您可以简单地通过@Interceptors( { MyInterceptor.class } ) 添加拦截器,然后添加第二个@MyInterceptorConfiguration(value=something)。

As bkail says in their answer here:

正如 bkail 在他们的回答中所说:

This is only possible with CDI stereotype annotations (see the interceptor bindings page for examples) in EE 6 (EJB 3.1).

这仅适用于 EE 6 (EJB 3.1) 中的 CDI 构造型注释(请参阅拦截器绑定页面以获取示例)。

回答by mdolanci

First annotation:

第一个注释:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FirstAnnotation {
  String value() default "";
}

Second annotation:

第二个注释:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SecondAnnotation {
  String value() default "";
}

Usage example:

用法示例:

public class Test {

  @SecondAnnotation("second annotation")
  @FirstAnnotation("first annotation")
  private String annotatedField1 = "value of field 1";

  @SecondAnnotation("second annotation")
  @FirstAnnotation("first annotation")
  private String annotatedField2 = "value of field 2";

  @SecondAnnotation("second annotation")
  private String annotatedField3 = "value of field 3";

  @FirstAnnotation("first annotation")
  private String annotatedField4 = "value of field 4";

  // Sample
  public static void processAnnotatedFields( final Object obj ) throws IllegalArgumentException, IllegalAccessException {

    for ( final Field field : getFieldsFornAnotation( obj, FirstAnnotation.class ) ) {
      // Do something with fields that are annotated with @FirstAnnotation
      final FirstAnnotation an = field.getAnnotation( FirstAnnotation.class );
      System.out.print( "@" +an.annotationType().getSimpleName()+ "(" +an.value()+ "): " );
      System.out.println( field.getName()+ " = '" +field.get(obj)+ "'" );
    }

    System.out.println();

    for ( final Field field : getFieldsFornAnotation( obj, SecondAnnotation.class ) ) {
      // Do something with fields that are annotated with @SecondAnnotation
      final SecondAnnotation an = field.getAnnotation( SecondAnnotation.class );
      System.out.print( "@" +an.annotationType().getSimpleName()+ "(" +an.value()+ "): " );
      System.out.println( field.getName()+ " = '" +field.get(obj)+ "'" );
    }

  }

  /**
   * Collect object fields annotated with "annotationClass"
   * This can be saved in static map to increase performance.
   */
  private static final Set<Field> getFieldsFornAnotation( final Object o, final Class<? extends Annotation> annotationClass ) {
    final Set<Field> fields = new LinkedHashSet<Field>();

    if ( o == null || annotationClass == null )
      return fields;

    for (final Field field : o.getClass().getDeclaredFields()) {
      if (field.isAnnotationPresent(annotationClass)) {
        field.setAccessible( true );
        fields.add( field );
      }
    }
    return fields;
  }

  public static void main(final String[] args) throws IllegalArgumentException, IllegalAccessException {

    processAnnotatedFields( new Test() );

  }

}

Result/output:

结果/输出:

@FirstAnnotation(first annotation): annotatedField1 = 'value of field 1'
@FirstAnnotation(first annotation): annotatedField2 = 'value of field 2'
@FirstAnnotation(first annotation): annotatedField4 = 'value of field 4'

@SecondAnnotation(second annotation): annotatedField1 = 'value of field 1'
@SecondAnnotation(second annotation): annotatedField2 = 'value of field 2'
@SecondAnnotation(second annotation): annotatedField3 = 'value of field 3'

回答by Prafulla

Yes I think Annotation itself provide annotation for that like @First, and @Second etc. so you can try that

是的,我认为 Annotation 本身为 @First 和 @Second 等提供了注释,因此您可以尝试