12

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

4

7 回答 7

8

您可以使用 @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 将首先执行。

于 2015-11-19T13:29:27.527 回答
2

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.

于 2013-03-08T23:45:40.350 回答
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(){}
}

当我尝试执行建议方法()时,以下是我收到的日志:

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

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

于 2016-08-15T02:20:44.123 回答
1

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

于 2015-05-14T13:20:36.170 回答
0

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

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

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

这仅在 EE 6 (EJB 3.1) 中使用 CDI 原型注释(参见拦截器绑定页面的示例)才有可能。

于 2013-01-14T12:49:26.790 回答
0

第一个注释:

@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'
于 2013-01-29T21:35:36.240 回答
-1

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

于 2013-01-14T12:43:20.560 回答