Spring 주해 프로 그래 밍 모델 지식 상세 설명

Spring 에는'원 주해'(Meta-Annotation)라 는 개념 이 있 는데 원 주 해 를 통 해 주해 의'파생 성'을 실현 한다.공식 적 으로 는'Annotation Hierarchy'라 고 한다.
원 주 해 는 무엇 입 니까?
이른바 원 주해 란 주해 에 표 시 된 주해 이다.이런 방식 으로 형 성 된 주해 등급 구조 에서 원 주 해 는 등급 구조의 위 에 있 고 나 는 그의 아버지 주해(Super Annotation)라 고 부 르 며 주 해 된 주 해 는 등급 구조의 아래 에 있 고 서브 주해(Sub Annotation)라 고 부른다.원 주 해 를 도입 하 는 목적 은 속성 재 작성(Attribute Override)의 목적 을 실현 하기 위 한 것 이다.
간단 한 예 를 들다.
하나의 클래스 홈 과 두 개의 주석 이 있 습 니 다.하 나 는@Parent 이 고 다른 하 나 는@Child 입 니 다.@Parent 는@Child 에 표시 되 어 있 습 니 다.@Child 는 Home 에 표시 되 어 있 습 니 다.모두 하나의 속성 만 있 습 니 다.name 이 라 고 합 니 다[email protected] 의 기본 값 이'John'이 고@Child.name 의 기본 값 은'Jack'입 니 다.
이때 홈 에서@Child.name 을 가 져 오 면'Jack'으로 돌아 가 야 합 니 다.걱정 이 없습니다.
그렇다면@Parent.name 을 가 져 오 면 무엇 을 되 돌려 야 합 니까?Spring 주해 의'파생 성',@Child.name [email protected] 에 따 르 면 결 과 를 되 돌려 주 는 것 도'Jack'입 니 다.
상술 한 예 중의 클래스 와 주 해 는 코드 가 대체로 다음 과 같다.

@interface Parent {
  String name() default "John";
}

@Parent
@interface Child {
  String name() default "Jack";
}

@Child
class Home { }
주해 계층 구조:
@Parent
@Child
'속성 재 작성'에 비해 또 다른 개념 은'속성 별명'(Alias)이 고 속성 별명 은 서로 등가 이다.
저 희 는 위의@Child 에 속성 value 를 추가 하고@AliasFor 를 사용 하여@Child.name 과@Child.value 를 서로 별명 으로 만 들 고 기본 값 은 빈 문자열 입 니 다.

@interface Child {
  @AliasFor("name")
  String value() default "";
 
  @AliasFor("value")
  String name() default "";
}
홈 에 표시 할 때@Child.value 에"Jack"값 을 설정 합 니 다.

@Child("Jack")
class Home { }
이 때@Child.name 을 가 져 오 든@Child.value 를 가 져 오 든 그 결 과 는 항상 같 습 니 다.모두"Jack"입 니 다.속성 별명 간 의 등가 성 을 설명 하 였 다.
속성 별명 과 속성 재 작성
속성 별명 과 속성 재 작성 은 전혀 다른 개념 이지 만 구분 하지 않 고 개념 을 모호 하 게 하면 일부 현상 이 기대 에 부합 되 지 않 아 의외 라 고 느 낄 수 있다.다음 사례 를 고려 하여@A.a 1,@A.a 2,@B.a1,@B.b,@C.c,@C.b 의 값 을 제시 합 니 다.

@interface A {
  String a1() default "1";
  String a2() default "1";
}

@A
@interface B {
  String a1() default "2";
  
  @AliasFor(value = "a2", annotation = A.class)
  String b() default "2";
}

@B
@interface C {
  @AliasFor(value = "a1", annotation = B.class)  
  String c() default "3";

  String b() default "3";
}
제 가 개념 을 파악 하지 못 하기 전에 답 은@A.a 1,@A.a 2,@B.a 1,@B.b,@C.c,@C.b 가 모두'3'이 라 고 생각 합 니 다.
이 유 는 다음 과 같다.
  • @C.c 는@B.a1 의 별명 이 고@B.a1 은@A.a1 을 다시 쓰기 때문에 이 3 자 는 하나의 체인 에 있 습 니 다.그들의 값 은 같 아야 합 니 다.'3'입 니 다.
  • @C.b 는@B.b,@B.b 는@A.a 2 의 별명 이기 때문에 이 3 자 도 하나의 체인 에 있 고 그들의 값 도 같 아야 하 며'3'이다.
  • 결 과 는 내 가 틀 렸 다[email protected],@B.b,@C.c,@C.b 의 값 은'3'이지 만@A.a 1,@A.a 2 의 값 은'2'이다.
    왜 그런 지 에 대해 서 는 속성 별명 과 속성 을 진지 하 게 이해 하고 이 두 개념 을 다시 쓰 자.
    공식 위 키 인용https://github.com/spring-projects/spring-framework/wiki/Spring-Annotation-Programming-Model그 중 에는 이 두 개념 에 대한 해명 이 있다.'Attribute Aliases and Overrides'1 절 에서 공식 원문 은 다음 과 같다.
    An attribute alias is an alias from one annotation attribute to another annotation attribute. Attributes within a set of aliases can be used interchangeably and are treated as equivalent. Attribute aliases can be categorized as follows.
    Explicit Aliases: if two attributes in one annotation are declared as aliases for each other via @AliasFor, they are explicit aliases.
    Implicit Aliases: if two or more attributes in one annotation are declared as explicit overrides for the same attribute in a meta-annotation via @AliasFor, they are implicit aliases.
    Transitive Implicit Aliases: given two or more attributes in one annotation that are declared as explicit overrides for attributes in meta-annotations via @AliasFor, if the attributes effectively override the same attribute in a meta-annotation following the law of transitivity, they are transitive implicit aliases.
    An attribute override is an annotation attribute that overrides (or shadows) an annotation attribute in a meta-annotation. Attribute overrides can be categorized as follows.
    Implicit Overrides: given attribute A in annotation @One and attribute A in annotation @Two, if @One is meta-annotated with @Two, then attribute A in annotation @One is an implicit override for attribute A in annotation @Two based solely on a naming convention (i.e., both attributes are named A).
    Explicit Overrides: if attribute A is declared as an alias for attribute B in a meta-annotation via @AliasFor, then A is an explicit override for B.
    Transitive Explicit Overrides: if attribute A in annotation @One is an explicit override for attribute B in annotation @Two and B is an explicit override for attribute C in annotation @Three, then A is a transitive explicit override for C following the law of transitivity.
    속성 별명 은 세 가지 가 있 는데 각각 명시 적 별명,암시 적 별명 과 전달 암시 적 별명 이다.'속성 별명'은 같은 주석 내부 에서 만 발생 할 수 있다.예 를 들 면:
    현식 별명(서로@AliasFor),@A.a 1 과@A.a 2,
    
    @interface A {
      @AliasFor("a2")
      String a1() default "";
    
      @AliasFor("a1")
      String a2() default "";
    }
    암시 적 별명(@AliasFor 에서 같은 속성 으로),@B.b1 과@B.b2
    
    @interface A {
      String a() default "";
    }
    
    @A
    @interface B {
      @AliasFor(value = "a", annotation = A.class)
      String b1() default "";
    
      @AliasFor(value = "a", annotation = A.class)
      String b2() default "";
    }
    암시 적 별명 전달(최종@AliasFor 에서 같은 속성 으로)@C.c1 과@C.c2
    
    @interface A {
      String a() default "";
    }
    
    @A
    @interface B {
      @AliasFor(value = "a", annotation = A.class)
      String b() default "";
    }
    
    @B
    @interface C {
      @AliasFor(value = "a", annotation = A.class)
      String c1() default "";
    
      @AliasFor(value = "b", annotation = B.class)
      String c2() default "";
    }
    속성 재 작성 도 세 가지 가 있 는데 그것 이 바로 암시 적 재 작성,명시 적 재 작성 과 전달 명시 적 재 작성 이다.'속성 재 작성'은 주석 사이 에서 만 발생 할 수 있다.예 를 들 면:
    암시 적 재 작성(동명 속성),@B.a 재 작성@A.a
    
    @interface A {
      String a() default "";
    }
    
    @A
    @interface B {
      String a() default "";
    }
    명시 적 재 작성(@AliasFor 필요),@B.b 재 작성@A.a
    
    @interface A {
      String a() default "";
    }
    
    @A
    @interface B {
      @AliasFor(value = "a", annotation = A.class)
      String b() default "";
    }
    전달 현식 재 작성(@AliasFor 필요),@C.c 재 작성@B.b,@B.b 재 작성@A.a,그래서@C.c 도@A.a 를 재 작성 합 니 다.
    
    @interface A {
      String a() default "";
    }
    
    @A
    @interface B {
      @AliasFor(value = "a", annotation = A.class)
      String b() default "";
    }
    
    @B
    @interface C {
      @AliasFor(value = "b", annotation = B.class)
      String c() default "";
    }
    잘 이해 한 후에 우 리 는 아까 의 문제 로 돌아 가서 사례 를 다음 과 같이 다시 붙 였 다.
    
    @interface A {
      String a1() default "1";
    
      String a2() default "1";
    }
    
    @A
    @interface B {
      String a1() default "2";
      
      @AliasFor(value = "a2", annotation = A.class)
      String b() default "2";
    }
    
    @B
    @interface C {
      @AliasFor(value = "a1", annotation = B.class)  
      String c() default "3";
    
      String b() default "3";
    }
    해답 절 차 는:
  • 주석 에 대해@C,@C.c="3",@C.b="3"
  • 주석@B,@B.a1 이@C.c 에 의 해 명시 적 으로 재 작성 되 었 기 때문에@[email protected]="3";@B.b 는@C.b 암시 적 으로 재 작성 되 었 기 때문에@[email protected]="3"
  • 주석 에 대해@A,@A.a 1 은@B.a1 은 식 으로 재 작성 되 었 기 때문에@A.a [email protected]="2";@A.a 2 는@B.b 명시 적 으로 재 작성 되 었 기 때문에@A.a [email protected]="2"
  • @A 와@C 사이 에는 아무런 관계 가 없 음 을 볼 수 있 습 니 다.여기 도'속성 별명'이 존재 하지 않 습 니 다.@AliasFor 를 사용 하지 않 으 면'속성 별명'입 니 다.
    '명시 적 전달 재 작성'에 대해 서 는'@A.a 1 은@B.a1 에 의 해 암시 적 으로 재 작성 되 고@B.a1 은@C.c 에 의 해 명시 적 으로 재 작성 된다'거나'@A.a 2 는@B.b 에 의 해 명시 적 으로 재 작성 되 고 B.b 는@C.b 에 의 해 암시 적 으로 재 작성 된다'는 식 으로 재 작성 관 계 는 전달 되 지 않 습 니 다.
    총결산
    속성 별명 은 세 가지 가 있 는데 각각 명시 적 별명,암시 적 별명 과 전달 암시 적 별명 이다.'속성 별명'은 같은 주석 내부 에서 만 발생 할 수 있다.속성 재 작성 도 세 가지 가 있 는데 그것 이 바로 암시 적 재 작성,명시 적 재 작성 과 전달 명시 적 재 작성 이다.'속성 재 작성'은 주석 사이 에서 만 발생 할 수 있다.
    후기
    Spring 은 주해 프로 그래 밍 모델 의 코드 구현 에 있어 주로 Annotated Element Utils 와 같은 종류 에서 시험 을 할 때 이 방법 을 사용 할 수 있 습 니 다.
    AnnotatedElementUtils#getMergedAnnotationAttributes。
    주의해 야 할 것 은'암시 적 재 작성'은 value 속성 에 적용 되 지 않 습 니 다.value 속성 은 상대 적 으로 특수 한 속성 인 것 같 습 니 다.
    다음 예제,@B.value 는 암시 적 으로@A.value 를 다시 쓰 지 않 습 니 다.
    
    @interface A {
      String value() default "a";
    }
    @A
    @interface B {
      String value() default "b";
    }
    그러나 속성 명 이 value 가 아니라면 암시 적 으로 다시 쓸 수 있 습 니 다[email protected] 암시 적 으로@A.xxx 를 다시 쓸 수 있 습 니 다.
    
    @interface A {
      String xxx() default "a";
    }
    
    @A
    @interface B {
      String xxx() default "b";
    }
    나 는 다음 과 같은 소스 코드 를 따라 갔다.소스 코드 에서 value 속성 에 대해 특별한 판단 을 한 것 을 발견 했다.코드 위 치 는 org.springframework.core.annotation.annotation.annotated Element Utils.Merged Annotation Attributes Processor\#postprocess 방법 에서 코드 세 션 은 다음 과 같다.
    
    // Implicit annotation attribute override based on convention
      else if (!AnnotationUtils.VALUE.equals(attributeName) && attributes.containsKey(attributeName)) {
        overrideAttribute(element, annotation, attributes, attributeName, attributeName);
      }
    그 중에서 AnnotationUtils.VALUE 는 상수 이 고 그 값 은'value'이다.value 속성 을 왜 특수 처리 해 야 하 는 지 공식 적 으로 설명 하지 못 했 습 니 다.많은 주석 이 하나의 속성 만 있 을 것 이 라 고 추측 합 니 다.프로 그래 밍 이 편리 하기 위해 서 는@A(value="hello World)가 필요 없 기 때문에@A("hello World")만 사용 하면 됩 니 다.이 경우 암시 적 으로 다시 쓰 면 인 코딩 자가 원 하 는 결과 가 아 닐 수 있 습 니 다.
    특히 명시 적 재 작성 은 이러한 특별한 처리 가 없 으 며,아래 예제@B.value 는 명시 적 으로@A.value 를 다시 씁 니 다.
    
    @interface A {
    
      String value() default "a";
    }
    
    @A
    @interface B {
    
      @AliasFor(annotation = A.class)
      String value() default "b";
    }
    본 논문 에서 다 루 는 Spring Boot 버 전>=2.0.2.RELEASE.
    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기