본문 바로가기

웹개발/Spring

[Spring] Annotation을 알아보자 - 1. 기본 개념과 직접 해보기

스프링에 입문한 Jay는 역시나 스프링 내부구조를 뜯어보는 것에 흥미가 생겼다. 

 

이 글은 https://dzone.com/articles/how-annotations-work-java를 참고했다. DZone에 재밌는 글이 많다. (실력자 볼 때마다 두근거린다. 마치 2대 600치는 장미란 선수를 볼 때의 헬스 빌런의 마음이랄까)

 

How Do Annotations Work in Java? - DZone Java

Let's discuss what annotations are, how they work, how to write custom annotations (with example code), valid scenarios for annotations, and lastly, annotations and ADF.

dzone.com

 

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이 위치할 수 있는 곳이다. 따로 설정하지 않으면 어디든 위치할 수 있다. 

Target이 가질 수 있는 7가지 속성 from 글 서두의 링크

결국 위와 같은 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를 만들어야 한다. 이건 다음에 알아보자.