Annotation
Annotation은 Java 1.5에 추가된 녀석으로 지금은 새로울게 없지만 당시만해도 이거뭐하는거야 했던 녀석이다.
Annotation이란?
Annotation의 사전적 의미는 주석이라는 뜻인데 다만 우리를 위한 주석은 아니고 컴파일러나 JVM, 프레임워크 등이 보는 주석이다.
즉 코드상에 annotation을 달아놓으면 상황에 따라 컴퍼일러가 읽어서 무슨 처리를 하고 프레임워크가 읽어서 무슨 처리를 하는 형태이다.
흔히 이제까지 봐왔던 annotation으로는 @Override나 @Deprecated등이 있다.
@Override라고 쓰고 override 문법을 지키지 않으면 컴파일 시 오류가 발생하고 이클립스에서도 오류가 표시되는 것을 경험한 적이 있을 것이다. @Deprecated가 선언된 메서드를 사용하려 하면 역시 이클립스가 읽어서 취소선을 쫙 그어준다.
@Deprecated
public String helloEng(String name) {
return "Hello " + name;
}
아무튼 이렇게 보조적인 역할을 하던 annotation이 스프링에서는 프로그래밍에 아주 적극적으로 사용된다. 그래서 잘 사용하지 못하면 혼돈의 늪에 빠지기 쉽다.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"file:src/main/webapp/WEB-INF/mvc-config.xml"})
@WebAppConfiguration
public class RequestMappingTest {
@Autowired
WebApplicationContext ctx;
}
이번 포스트에서는 annotation을 어떻게 분석하고 사용해야 하는지 살펴보자.
Annotation 분석
에너테이션의 구성
에너테이션은 메타 에너테이션과 에너테이션 선언, 에너테이션 속성 정의의 3 부분으로 이뤄진다. 예를 들어 다음은 SupressWarnings라는 애너테이션의 소스 코드이다.
메타 에너테이션이란 에너테이션에 선언된 에너테이션들로 애너테이션 설정과 관련된 내용을 담는다.
에너테이션을 선언할 때는 @interface 키워드를 이용한다.
에너테이션 속성은 에너테이션을 사용할 때 전달해야하는 속성들을 나열한다.
메타 에너테이션
meta annotation이란 에너테이션에 선언된 에너테이션으로 에너테이션 사용과 관련된 정보를 제공한다.
모든 애너테이션에는 @Retnetion과 @Target이 선언되어있다.
먼저 @Retention은 에너테이션이 얼마나 오래동안 에너테이션 정보를 유지할 것인지를 설정한다. @Retention에는 RetentionPolicy를 이용해서 이 기간을 선언할 수 있는데 RetentionPolicy에 상수로 정의되어있다.
상수값 |
범위 |
SOURCE |
컴파일러가 사용하며 컴파일 결과물인 클래스 파일 안에는 포함되지 않음 |
CLASS |
컴파일 시 클래스 안에 포함되지만 VM에서는 무시되며 reflaction 시에는 정보를 얻을 수 없다. |
RUNTIME |
컴파일 시 포함되며 VM에서 인식하며 feflaction 시 정보를 얻을 수 있다. |
@Retention 정보는 사실 사용하는 입장에서는 그다지 중요하지 않은것 같다.
@Target은 매우 중요한 속성인데 에너테이션을 어디에서 사용할 수 있는지 지정한다. @Target에서 사용 가능한 속성들은 ElementType에 상수값으로 선언되어있는데 아래와 같다.
상수값 |
범위 |
TYPE |
클래스, 인터페이스 또는 enum 타입 |
FIELD |
필드 또는 enum 타입의 값 |
METHOD |
메서드 |
PARAMETER |
메서드의 파라미터 |
CONSTRUCTOR |
생성자 |
LOCAL_VARIABLE |
로컬 변수 |
ANNOTATION_TYPE |
다른 에너테이션 |
PACKAGE |
패키지 |
예를 들어 아래와 Qualifier라는 에너테이션을 살펴보자.
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE,
ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier {
String value() default "";
}
@Qualifer의 @Target에 살펴보면 FIELD, METHOD, PARAMETER, TYPE, ANNOTATION_TYPE에 사용될 수 있는 에너테이션이기 때문에 생성자에는 사용할 수 없다는 것을 알 수 있다.
에너테이션의 속성
에너테이션에는 미리 지정된 속성에 값을 전달할 수 있다. 그런데 경우에 따라 다양한 형태로 값이 전달되므로 주의가 필요하다.
일단 속성은 마치 추상 메서드 처럼 선언하고 일반 속성처럼 key=value 의 형태로 사용한다.이때 메서드의 이름은 속성의 이름이 되고 리턴 타입은 속성의 타입이다.
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE,
ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier {
String value() default "";
}
위 @Qualifier에는 value라는 속성이 선언되어있으며 타입은 문자열이다. default 로 "" 이 할당되기 때문에 반드시 값을 할당할 필요는 없다.
속성 사용시 주의할 사항은 아래와 같다.
- 설정하려는 속성이 value 하나인 경우는 속성 이름인 value를 생략할 수 있다.
- 타입은 일반 자바 타입을 사용할 수 있으며 배열의 길이가 1일 때는 {}를 생략할 수 있다.
아래와 같이 ComponentScan 에너테이션을 사용할 때 잘못 선언된 것들을 찾아보자.