들어가면서
프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것이 바로 어노테이션이다. 어노테이션은 주석(comment)처럼 프로그래밍 언어에 영향을 미치지 않으면서도 다른 프로그램에게 유용한 정보를 제공할 수 있다는 장점이 있다.
어노테이션의 동작 원리
결론부터 말하자면 어노테이션은 컴파일과정에서 수행된다.(런타임이 아니다.)
모든 자바 소스파일들은 parser에 들어간다. parser는 Abstract Syntax Trees를 생성하고, 컴파일러의 symbol table을 채운다. 그 다음, 각 어노테이션에 대해 해당하는 Annotation Processor가 호출되며, 이는 새로운 소스 파일들을 생성할 수 있다.(어노테이션에 해당하는 부분이 코드로 바뀌어 새로운 소스파일을 생성한다.)
새로 생성된 모든 소스 파일들은 다시 parser로 피드백되어 parsing되어야 하며 추가적인 어노테이션을 포함할 수 있다. 마지막으로, 새로운 소스 파일이 더 이상 생성되지 않으면, syntax tree들이 클래스 파일로 변환된다.(.class) 이 마지막 단계에는 외부 라이브러리에 대한 참조를 해결하는 과정이 포함되며, 이 라이브러리의 클래스들도 컴파일되어야 한다. 그러나 이들은 어노테이션 처리 대상이 되지 않는다.
주목해야 할 중요한 점은 어노테이션 프로세서는 새로운 소스 파일만을 생성할 수 있으며 기존 파일을 수정할 수 없다는 것이다. 또한 javac
가 컴파일 중에 자체 JVM 내에서 어노테이션 프로세서를 실행한다는 것을 아는 것도 중요하다. 이는 소스 파일을 생성하기 위해 임의의 Java 라이브러리를 사용할 수 있으며 테스트도 작성할 수 있다는 것을 의미한다.
일부 어노테이션은 런타임에도 사용 가능하도록 설계되었다.(@Retention(RetentionPolicy.RUNTIME)) 이런 어노테이션은 컴파일 후에도 클래스 파일에 정보가 남아있어, 런타임에 Reflection으로 접근할 수 있다.
class.getAnnotations()와 컴파일타임 어노테이션
위에서 말하는 getAnnotations()는 런타임 어노테이션에 해당하는 어노테이션들을 불러온다. 그래서 컴파일 타임의 어노테이션들은 불러오지 않는다. 예시를 보자.
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@SuppressWarnings({})
public class HelloController {
@GetMapping("/hello")
public String hello(@RequestParam(defaultValue = "") String name) {
return "Hello " + name;
}
}
이렇게 간단한 컨트롤러 코드를 작성하였다. 이 클래스에 사용한 어노테이션은 총 두개, @RestController
, @SuppressWarnings
이다. 이중에서 @RestController
는 런타임시 적용되는 어노테이션이고, @SuppressWarnings
는 컴파일타임시 적용되는 어노테이션이다.
둘의 정보를 모두 볼 수 있게 코드를 작성하고 결과를 보자.
Class<?> clazz = HelloController.class;
System.out.println(Arrays.toString(clazz.getAnnotations()));
- 결과
보다시피 RestController 하나만 출력되는 것을 볼 수 있다.
표준 어노테이션(Standard Annotations)
자바에서 기본적으로 제공하는 애너테이션들은 몇 개 없다. 그나마 이들의 일부는 ‘메타 어노테이션(meta annotation)‘으로 어노테이션을 정의하는데 사용되는 어노테이션의 어노테이션이다.
- 자바에서 기본적으로 제공하는 표준 어노테이션(*이 붙은 것은 메타 어노테이션)
메타 어노테이션(meta anotation)
앞에서 설명했듯이, 어노테이션을 위한 어노테이션이다. 실제 @Controller
어노테이션 코드를 살펴보자.
package org.springframework.stereotype;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
@AliasFor(
annotation = Component.class
)
String value() default "";
}
Controller 어노테이션을 보면 다른 어노테이션들이 있는 것을 볼 수 있다. 메타 어노테이션은 어노테이션을 정의할 때, 어노테이션의 적용대상(Target)이나 유지기간(Retention) 등을 지정하는 데 사용된다.
메타 어노테이션은 ‘java.lang.annotation’ 패키지에 포함되어 있다.
나머지 상세한 어노테이션들에 대한 설명은 위 표에 하이퍼링크를 달거나, 따로 정리해두려고 한다.
출처: