如何确保java中的注释执行顺序?

时间:2013-01-14 12:30:19

标签: java spring annotations

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

7 个答案:

答案 0 :(得分:4)

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

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

示例:

第一个注释:

@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
    }
}

第二个注释:

@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
    }

使用它们:

@CustomAnnotationTwo
@CustomAnnotation
public void someMethod(){
}

在此示例中,CustomAnnotationInterceptor将首先执行。

答案 1 :(得分:2)

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

以下是我的示例代码:

@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(){}
}

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

A_Aspect
B_Aspect

我更改了注释声明序列:

@A
@B  
public void advisedMethod(){}

以下是日志:

A_Aspect
B_Aspect

我将注释@A重命名为@C,以下是日志:

A_Aspect
B_Aspect

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

B_Aspect
C_Aspect

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

的文档

答案 2 :(得分:1)

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

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

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

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

答案 3 :(得分:0)

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

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

正如bkail在their answer here中所说:

  

这只适用于CDI刻板印象   注释(见拦截器   EE 6(EJB 3.1)中的示例绑定页面。

答案 4 :(得分:0)

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

答案 5 :(得分:-1)

是的我觉得Annotation本身为@First和@Second等提供了注释,所以你可以试试

答案 6 :(得分:-1)

第一个注释:

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

第二个注释:

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

用法示例:

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() );

  }

}

结果/输出:

@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'