스프링에 입문한 Jay는 역시나 스프링 내부구조를 뜯어보는 것에 흥미가 생겼다.
이 글은 https://dzone.com/articles/how-annotations-work-java를 참고했다. DZone에 재밌는 글이 많다. (실력자 볼 때마다 두근거린다. 마치 2대 600치는 장미란 선수를 볼 때의 헬스 빌런의 마음이랄까)
1. Annotation이란 무엇인가?
일단 Annotation이 뭔지부터 알아보자.
@Controller // Controller Annotation이 있으면 관련 객체를 생성해서 Spring Container에 얘를 넣어둠
public class MemberController {
MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
저기에 @Controller나 @Autowired 같은 친구들이 Annotation이다.
Java Language Specification (JLS)에서는 Annotation을
"프로그램 construct와 관련된 정보를 나타내지만 런타임 때 영향을 미치지 않는 마커다"라고 말하고
누군가는 metadata라고 말한다.
무슨 말인지 모르겠다.
예를 들어보자.
위의 코드처럼 MemberController 함수 위에 @Autowired 라는 Annotation이 추가되었지만 MemberController의 행동이 바뀌는 건 아니다. MemberController 함수는 그대로 있고, @Autowired Annotation에 대응되는 Processor가 적절한 행동을 하게 된다. 지금 @Autowired는 Dependency Injection을 지시하고 있다. 그렇기 때문에 컴파일 타임 때 Bean Factory에서 해당하는 Bean을 삽입해 줄 것이다.
그리고 Annotation도 Annotation을 가질 수 있다.
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any (or empty String otherwise)
*/
@AliasFor(annotation = Component.class)
String value() default "";
}
분명 Controller는 이전까지 @Controller로서 Annotation이었는데 이 Annotation을 타고 들어가자 또 Annotation이 있다. 그것도 여러 개나!!
그렇다면 Controller라는 이름의 Annotation은 @Target ~ @Component의 수식을 받고 있으니 저 각각의 Annotation도 누군가의 수식을 받고 있지 않을까?
한번 계속 파보자. 제일 마지막에 위치한 @Component를 파본다.
@Component
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any (or empty String otherwise)
*/
String value() default "";
}
띠용... Component 너마저...
@Interface는 "내가 선언한(Customized) Annotation"이라는 뜻이다. 위에 있었던 Controller와 Component 모두 내가 선언한 Annotation이다. 자, 내가 선언한 Annotation이 있으면 내가 선언하지 않은 Annotation도 있을 것 같다.
더 파보자.
자 위에서 @Indexed를 파본다.
@Indexed
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Indexed {
}
하... @Indexed도 @Interface가 있는 걸 보니 만들어진 Annotation이다. 그런데 내부 구현이 하나도 없다. 그냥 존재만 하는 녀석이다. @Override도 위와 같은 형태라고 알려져 있다(내부 구현이 없는.) 이런 Annotation에 대해서는 다음에 파보자.
어랏??! 근데 잘 보면 아까부터 반복되는 Annotation이 있다
@Target @Retention @Documented 은 아까부터 반복되고 있다. 얘들이 대체 뭐길래 반복되는가??
J2SE 5.0에서는 4가지 Annotation을 java.lang.annotation package에서 제공한다.
@Documented : Javadocs에 이 Annotation이 있는가
@Retention : Annotation이 필요한가. 즉, Annotation이 유지될 기간을 의미한다. Indexed는 RUNTIME으로 설정되어있다. 이것 외에 SOURCE(Compile Time때 버려진다. 그래서 ByteCode에는 포함이 안된다.), CLASS(class load때 버려진다. bytecode-level post-processing 때 유용하다. 놀랍게도 이 설정이 기본값이다.)가 있다.
@Target : Annotation이 위치할 수 있는 곳이다. 따로 설정하지 않으면 어디든 위치할 수 있다.
결국 위와 같은 Annotation은 Java가 기본적으로 제공하는 패키지에 있고, 이들을 이용해서 우리가 원하는 Annotation을 새로 만들 수 있다는 뜻이다.
예를 들어보자.
// 원하는 Interface를 만든다.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Interface Love {
public enum Sex {MALE, FEMALE, NONE}
public enum Status {STARTED, NOT_STARTED}
Sex sex() default Sex.NONE;
Status status() default Status.NOT_STARTED;
}
@Love(status = Love.Status.STARTED)
public void something() {
System.out.println("SOMETHING IN MIND");
}
사랑에 대한 Annotation을 만들었다.
그리고 이 Annotation을 실제 코드에 적용할 수도 있는데 이 때 이 Annotation을 처리해줄 적절한 Processor를 만들어야 한다. 이건 다음에 알아보자.
'웹개발 > Spring' 카테고리의 다른 글
[Spring]Spring JPA의 1차 캐시는 얼마나 이득을 줄 수 있을까. (0) | 2020.11.08 |
---|---|
[Spring] Annotation을 알아보자 - 2. Annotation은 어떻게 처리될까? (0) | 2020.08.06 |
[Spring] 테스트 코드는 순서대로 실행되지 않는다. (0) | 2020.08.04 |