복붙노트

[SPRING] 어떻게 자바에서 주석 실행 순서를 보장하기 위해?

SPRING

어떻게 자바에서 주석 실행 순서를 보장하기 위해?

2 개의 사용자 지정 주석이 있지만 항상 다른 주석보다 먼저 실행해야합니다. 어떻게해야합니까? 어떤 종류의 순서가 있나요? 아니면 추가 메서드 정의로할까요?

해결법

  1. ==============================

    1.@Order 주석으로 맞춤 주석의 순서를 확인할 수 있습니다.

    @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가 먼저 실행됩니다.

  2. ==============================

    2.나는 이것이 매우 오래된 질문이라는 것을 알고 있지만, 나는 단지 나의 발견을 문서화하고 싶었다. 누구나 확인할 수 있습니까? 이 페이지에서 @Order 주석이 사용되지 않는 한 주석 문서의 실행은 정의되지 않는다고 Spring 문서에서 이미 언급되었습니다. Aspect 클래스의 이름을 바꾸려고 시도하고 여러 번 테스트 한 결과 Aspect 클래스가 이름의 사전 순으로 실행되고 결과가 일관됨을 발견했습니다.

    나는 이것이 매우 오래된 질문이라는 것을 알고 있지만, 나는 단지 나의 발견을 문서화하고 싶었다. 누구나 확인할 수 있습니까? 이 페이지에서 @Order 주석이 사용되지 않는 한 주석 문서의 실행은 정의되지 않는다고 Spring 문서에서 이미 언급되었습니다. 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(){}
    }
    

    advisedMethod ()를 실행하려고 할 때받은 로그는 다음과 같습니다.

    A_Aspect
    B_Aspect
    

    주석 선언 순서를 변경했습니다.

    @A
    @B  
    public void advisedMethod(){}
    

    다음은 로그입니다.

    A_Aspect
    B_Aspect
    

    내가 Annotation @A를 @C로 바꿨다. 다음은 로그들이다.

    A_Aspect
    B_Aspect
    

    하지만 Aspect 클래스 A_Aspect의 이름을 C_Aspect로 변경하려고하면 다음과 같은 로그가 표시됩니다.

    B_Aspect
    C_Aspect
    

    내가 말했듯이, 나는 이것에 대한 어떤 문서도 찾을 수 없었기 때문에 누군가가 이것을 확인하기를 원한다.

  3. ==============================

    3.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는 AspectJ와 동일한 선행 규칙을 따라 advice 실행 순서를 결정한다. 우선 순위가 가장 높은 조언이 먼저 실행됩니다 (사전 조언 2 개가 주어 지므로 가장 우선 순위가 높은 조언이 먼저 실행됩니다). 조인 포인트에서 "나가는 중"에서 가장 높은 우선 순위 조언이 마지막으로 실행됩니다 (따라서 두 가지 조언이 주어지면 우선 순위가 가장 높은 조언이 두 번째 실행됩니다).

    서로 다른 측면에서 정의 된 두 가지 조언이 모두 동일한 조인 포인트에서 실행되어야하는 경우 달리 지정하지 않으면 실행 순서가 정의되지 않습니다. 우선 순위를 지정하여 실행 순서를 제어 할 수 있습니다. 이는 aspect 클래스에서 org.springframework.core.Ordered 인터페이스를 구현하거나 Order 애노테이션으로 annotation함으로써 일반적인 Spring 방식으로 수행된다. 두 가지 측면에서 보면 Ordered.getValue () (또는 주석 값)에서 낮은 값을 반환하는 aspect가 더 높은 우선 순위를 갖습니다.

    동일한 측면에서 정의 된 두 가지 조언이 모두 같은 조인 포인트에서 실행되어야하는 경우 순서는 정의되지 않습니다 (javac 컴파일 클래스의 리플렉션을 통해 선언 순서를 검색 할 방법이 없으므로). 이러한 애스펙트 메소드를 각 애스펙트 클래스의 조인 포인트 당 하나의 advice 메소드로 축소 시키거나 aspect의 레벨에서 정렬 할 수있는 별도의 애스펙트 클래스로 advice 조각을 리팩터링하는 것을 고려하십시오.

  4. ==============================

    4.EJB 인터셉터를 사용하여이를 수행 할 수 있습니다.

    EJB 인터셉터를 사용하여이를 수행 할 수 있습니다.

    @Interceptors ({MyInterceptor.class})를 통해 인터셉터를 추가 한 다음 두 번째 @MyInterceptorConfiguration (value = something)을 추가하면됩니다.

    bkail이 대답 할 때 다음과 같이 말합니다.

  5. ==============================

    5.Checkout https://stackoverflow.com/a/30222541/810109 : 적어도 Java 8에서는 보장 된 순서로 주석을 검색 할 수 있으므로 올바른 순서로 주석을 작성해야합니다.

    Checkout https://stackoverflow.com/a/30222541/810109 : 적어도 Java 8에서는 보장 된 순서로 주석을 검색 할 수 있으므로 올바른 순서로 주석을 작성해야합니다.

  6. ==============================

    6.그렇습니다. 주석 자체는 @First, @Second 등과 같은 주석을 제공한다고 생각합니다.

    그렇습니다. 주석 자체는 @First, @Second 등과 같은 주석을 제공한다고 생각합니다.

  7. ==============================

    7.첫 번째 주석 :

    첫 번째 주석 :

    @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'
    
  8. from https://stackoverflow.com/questions/14318438/how-to-ensure-annotations-execution-order-in-java by cc-by-sa and MIT license